brawsr Python SDK
The official synchronous Python client for brawsr sessions, checkpoints, rewind, fork, and CDP handoff. It turns asynchronous API operations into one bounded method call; it does not bundle or proxy a browser library.
Published on PyPI as brawsr. Requires Python 3.11+.
Install
pip install brawsr
Install your browser client separately, for example:
pip install playwright
Session and browser connection
from brawsr import BrawsrClient
from playwright.sync_api import sync_playwright
with BrawsrClient() as brawsr: # reads BRAWSR_API_KEY
session = brawsr.create_session(ttl_seconds=300, display_label="checkout retry")
try:
with sync_playwright() as playwright:
connection = brawsr.connect_cdp(session)
browser = playwright.chromium.connect_over_cdp(
connection.endpoint_url,
headers=connection.headers,
)
page = browser.contexts[0].pages[0]
page.goto("https://example.com")
print(page.title())
finally:
brawsr.close_session(session.id)
The production API endpoint is built in as https://api.brawsr.io. Pass
base_url="http://localhost:8080" explicitly when testing against another
deployment. The client can also receive api_key explicitly instead of reading
BRAWSR_API_KEY.
connect_cdp returns immutable connection data. The SDK does not retain the
API key in a browser object or speak CDP itself.
get_session(id) returns cdp_url only while the session is attachable, so a
restarted process can fetch an active session and pass it directly to
connect_cdp. Calling connect_cdp with a closed or expired Session raises a
clear local error.
Session workspace
# Pages use opaque cursors; iterators fetch each page lazily.
for session in brawsr.iterate_sessions(status="active"):
print(session.id, session.display_label, session.attachable)
brawsr.update_session(session.id, display_label="") # clear the label
# Capture history is an audit view and can include deleted checkpoints.
captures = brawsr.list_checkpoints(session.id)
# Ancestry contains the current rewind candidates. The server revalidates the
# selected capture when rewind is requested.
capture = next(brawsr.iterate_ancestry(session.id))
restored = brawsr.rewind(session.id, capture)
activity = brawsr.list_activity(session.id)
lineage = brawsr.get_lineage(session.id)
for child in brawsr.iterate_lineage_children(session.id):
print(child.ordinal, child.session.id)
Session lists are newest-first. They support exact status, display_label,
and session_id filters, case-insensitive label search, and inclusive
created_from / exclusive created_before creation-time bounds. get_session
and update_session return SessionDetail, including collection counts,
an optional active lifecycle operation, and the canonical collection paths.
get_lineage returns one hop: the selected session, its optional parent edge,
and a bounded page of direct children. Fetch a child session's lineage to
expand a nested fork tree.
Checkpoint and rewind
checkpoint = brawsr.create_checkpoint(
session.id,
label="before-submit",
timeout=30.0,
)
# Continue browser work. This state is intentionally newer than the checkpoint.
page.fill("textarea", "draft that should be discarded")
# A label, checkpoint ID, Capture, Checkpoint, or CheckpointResult is accepted.
restored = brawsr.rewind(session.id, checkpoint)
# Rewind replaces the browser process. The old Browser/Page handles are stale.
# Connect again and rediscover the default context and its pages.
connection = brawsr.connect_cdp(restored)
browser = playwright.chromium.connect_over_cdp(
connection.endpoint_url,
headers=connection.headers,
)
restored_context = browser.contexts[0]
restored_pages = restored_context.pages
# The early rewind result is already CDP-usable. Wait only before another
# lifecycle mutation on this same session (for example checkpoint or close).
brawsr.wait_rewind(restored.operation_id)
create_checkpoint, rewind, fork, and delete_checkpoint each send one mutation.
When the API returns 202 Accepted, the SDK polls only the operation resource
and returns the final result. Callers do not need to implement polling.
Checkpoint labels are case-sensitive and unique among live checkpoints in a session. A label that has the checkpoint-ID shape is rejected; use the returned ID when an immutable reference is required.
Resources and operations
create_session,list_sessions,iterate_sessions,get_session,update_session,close_sessioncreate_checkpoint,get_checkpoint,list_checkpoints,iterate_checkpoints,delete_checkpointlist_ancestry,iterate_ancestrylist_activity,iterate_activityget_lineage,iterate_lineage_childrenrewindfork,close_sessionsget_operation,wait_operation,wait_checkpoint,wait_rewind,wait_forkconnect_cdp
Collection iterators are lazy and fetch one bounded page at a time. Cursors are opaque and must be passed back unchanged.
Every waiter accepts a timeout and optional threading.Event. Stopping a
waiter does not cancel work already admitted by the server. The
operation-specific waiters return the same typed result as the corresponding
mutation, including the restored CDP URL after rewind; callers never need to
decode raw operation results. get_operation and wait_operation remain
available for generic observability.
Fork and explicit cleanup
forked = brawsr.fork(
session.id,
checkpoint,
n=3,
ttl_seconds=300,
timeout=30.0,
)
for child in forked.children:
connection = brawsr.connect_cdp(child)
# Each child is an independent session. Attach with your browser library.
print(child.branch_index, child.session_id, connection.endpoint_url)
outcomes = brawsr.close_sessions(forked, concurrency=3)
for outcome in outcomes:
if not outcome.ok:
print("close failed", outcome.session_id, outcome.error)
The returned children are immutable and ordered by branch_index. The source
session remains open. Children may checkpoint, rewind, or fork again; there is
no browser-state merge. close_sessions never selects a winner, closes the
source, or hides partial failures. It accepts a fork result, child objects, or
session IDs and preserves input order in its outcome tuple.
By default, cleanup requests use isolated HTTP sessions so concurrency does
not share mutable requests.Session state. A caller that injects a custom
session may also inject a session_factory; without one, cleanup safely
serializes while retaining identical ordered outcomes.
Errors and recovery
BrawsrError: common base for API, transport, operation, response, timeout, cancellation, and closed-client failures.BrawsrApiError: safe API envelope withstatus_code, stablecode,request_id, optionaloperation_id,retryable, andretry_after_ms.BrawsrResponseError: the API returned JSON that does not match the public response contract.BrawsrOperationError: the server operation reachedfailed.BrawsrWaitTimeoutError/BrawsrWaitCancelledError: local waiting stopped; server work may still complete. For an admitted mutation,operation_idandidempotency_keyremain available programmatically for recovery.BrawsrTransportError: the transport outcome is ambiguous. Itsidempotency_keyis available programmatically for recovery but is omitted from the message.
The client does not retry an ambiguous mutation by default. Advanced callers
may provide is_pre_response_connection_error; only a definitely pre-response
failure is retried, at most once, with the same idempotency key.
Resume a timed-out rewind without resending it:
try:
restored = brawsr.rewind(session.id, checkpoint, timeout=1.0)
except BrawsrWaitTimeoutError as error:
if error.operation_id is None:
raise
restored = brawsr.wait_rewind(error.operation_id, timeout=30.0)
connection = brawsr.connect_cdp(restored)
browser = playwright.chromium.connect_over_cdp(
connection.endpoint_url,
headers=connection.headers,
)
Rewind restores browser/client state, not side effects already committed by a remote website. Long-lived WSS, SSE, or WebRTC connections may need application-level reconnection after restore.
See examples/rewind_playwright.py for an executable reconnect story that
rejects a stale page handle and rediscovers the restored pages. A classic
Selenium WebDriver session cannot be rebound to the replacement browser in
v0.1; a later WebDriver/BiDi adapter owns that contract.
Development
python -m pip install uv==0.10.9
uv sync --locked --all-extras
uv run ruff format --check src tests scripts examples
uv run ruff check src tests scripts examples
uv run mypy src
uv run python scripts/verify_contract.py
uv run pytest -q
uv run python scripts/verify_package.py
The package check uses the release-pinned Python 3.11 + Hatchling 1.31.0 toolchain, builds each archive twice with a fixed source epoch, compares contents and SHA-256, and imports the wheel from a clean temporary install. Use Python 3.11 for this release-only gate; the installed SDK remains supported on newer Python versions.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file brawsr-0.1.1.tar.gz.
File metadata
- Download URL: brawsr-0.1.1.tar.gz
- Upload date:
- Size: 18.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
619c9c02b075d518323af36c8da3457bacedeb631dae2887e71253bfdd8144d6
|
|
| MD5 |
c0943a05cf065d97970ddf8d340733a7
|
|
| BLAKE2b-256 |
ef02343b5fe0d4c53ed467cf447e5cb33f91d40d27c4ddfa5d08c59e2abeeee6
|
Provenance
The following attestation bundles were made for brawsr-0.1.1.tar.gz:
Publisher:
publish.yml on brawsr/sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
brawsr-0.1.1.tar.gz -
Subject digest:
619c9c02b075d518323af36c8da3457bacedeb631dae2887e71253bfdd8144d6 - Sigstore transparency entry: 2395082139
- Sigstore integration time:
-
Permalink:
brawsr/sdk-python@f997f42d37c80034e9001e6a43da695909e78edb -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/brawsr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f997f42d37c80034e9001e6a43da695909e78edb -
Trigger Event:
release
-
Statement type:
File details
Details for the file brawsr-0.1.1-py3-none-any.whl.
File metadata
- Download URL: brawsr-0.1.1-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8a123f3cacf2eb4b3dd630c077aff85a50cd37eafb127f6f69b6477512a5794
|
|
| MD5 |
43e88666133f03f68d58102b61c7323d
|
|
| BLAKE2b-256 |
fcbbadef667d467191fe47b731ae110d171497211dd75a580375423540053792
|
Provenance
The following attestation bundles were made for brawsr-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on brawsr/sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
brawsr-0.1.1-py3-none-any.whl -
Subject digest:
f8a123f3cacf2eb4b3dd630c077aff85a50cd37eafb127f6f69b6477512a5794 - Sigstore transparency entry: 2395083020
- Sigstore integration time:
-
Permalink:
brawsr/sdk-python@f997f42d37c80034e9001e6a43da695909e78edb -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/brawsr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f997f42d37c80034e9001e6a43da695909e78edb -
Trigger Event:
release
-
Statement type: