Pravda is a Python library for durable web evidence capture. It drives a
remote Playwright browser to capture rendered HTML, full-page screenshots,
and HAR recordings with response bodies, written content-addressed to any
fsspec-compatible backend. Captures return immutable Snapshot values;
persisting them is the application's policy.
- Browser: a remote Playwright Chromium WebSocket endpoint.
- Storage: any fsspec URL (
./data,s3://bucket,gs://bucket, …).
Python 3.12+:
pip install opensanctions-pravda
pip install opensanctions-pravda[unmhtml] # with standalone HTML derivationBuild a Storage once, then a long-lived Pravda over it. Instances are
safe to reuse: concurrent captures each open their own connection, and the
storage handle reads artifacts back later.
from pravda import Pravda, Storage
storage = Storage.from_url("./data")
pravda = Pravda("ws://localhost:3000", storage)
snapshot = await pravda.capture("https://example.com")
print(snapshot.id, snapshot.http_status, snapshot.rendered_html)capture() returns a Snapshot with client-minted id and captured_at;
artifact fields are storage-relative paths, read back with
storage.read_artifact(path). A failed capture is returned with error
set, not raised.
Pravda(browser_ws_url, storage, *, timeouts):
timeouts— wall-clock budgets bounding one capture attempt. Defaults are sensible; see theTimeoutsdocstring.
By default Pravda navigates, waits for load, and captures. For custom
navigation or interaction, pass an async drive(page, url) callback:
async def drive(page, url):
await page.goto(url, wait_until="commit")
await page.wait_for_selector(".results")
snapshot = await pravda.capture("https://example.com", drive=drive)The callback owns navigation; Pravda owns capture and cleanup. Playwright
errors from drive are returned as failed snapshots; other exceptions
propagate and capture nothing. Viewer-handled downloads
(e.g. PDFs) surface in drive as Playwright's Download is starting;
Pravda recovers the body into the HAR.
path = await snapshot.derive_standalone_html(storage)Derives a self-contained rendering — stylesheets inlined, images embedded
as data URIs, active content sanitized — from the snapshot's stored
evidence, stores it like any other artifact, and returns its path. Needs
no browser, so it works in any process. Requires the unmhtml extra.
Artifacts are content-addressed files under the captured page's hostname
(example.com/<sha1>.html). The Snapshot records each artifact's path:
rendered_html, screenshot, and every HAR response.content._file.
Requires uv and a remote Playwright browser
endpoint. Environment variables live in .env, which uv does not read
automatically:
uv sync
cp .env.example .env
uv run --env-file .env pytest
uv run ruff check .
uv run ruff format --check .MIT — see LICENSE.