Docs / Python SDK

Python SDK

The official Python client for AgentBrowser — a browser that acts on your agents' behalf. Standard library only, zero dependencies. Python 3.8+.

Install

A real, versioned, installable package (pyproject.toml, semantic version in agentbrowser.__version__):

pip install ./sdk/python          # or: pip install -e ./sdk/python for development

Still just one small package if you'd rather vendor it — copy the whole agentbrowser/ directory (not a single file anymore, since __init__.py is now versioned and packaged) into your project:

cp -r sdk/python/agentbrowser your_project/

Quickstart

from agentbrowser import AgentBrowser

ab = AgentBrowser(api_key="gbk_...")            # from the console → API keys

with ab.session(url="https://example.com", record=True) as s:
    png = s.screenshot()                        # -> bytes (PNG)
    pdf = s.pdf()                               # -> bytes (PDF)
    data = s.extract_all({"title": "h1", "price": ".price"})
    print(data)                                 # {"title": "...", "price": "..."}
# session auto-closes; because record=True the bundle is persisted server-side

# Use a separate non-recorded session for credentials. Once a hosted credential
# is filled, page, cookie, screenshot, and PDF reads are refused for that session.
with ab.session(url="https://example.com/login") as s:
    s.login("app-login")                        # hosted vault; may await approval
    s.click("#submit")

# Later, fetch the recording:
for rec in ab.recordings():
    open("session.tar.gz", "wb").write(ab.download_recording(rec["id"]))

Bring your own framework (raw CDP)

s = ab.session(cdp=True, url="https://example.com", profile="mobile")
print(s.cdp_url)     # wss://app.getagentbrowser.com/api/sessions/<id>/cdp?ticket=...
# The URL is ready to use — it carries a short-lived ticket scoped to this one
# session, so your account key never ends up in a log. Just:
#   browser = playwright.chromium.connect_over_cdp(s.cdp_url)

The dedicated browser honors url and profile (desktop or mobile) at launch. All hosted traffic is forced through a node-owned public-only proxy that re-resolves and validates every HTTP request and HTTPS tunnel; loopback, private, link-local, metadata, mixed public/private DNS answers, and non-HTTP navigation are rejected. Caller proxy and proxy_bypass options are rejected because they would bypass that boundary. Do not combine cdp=True with record, dom, or no_video; raw-CDP capture is owned by your Playwright/Puppeteer/CDP client.

Use the returned cdp_url unchanged: its ticket is short-lived and scoped to that session. A client that constructs the session CDP endpoint itself must send Authorization: Bearer gbk_... with a key carrying sessions:write. Never append a reusable API key as ?key=.

Structured action output has fixed safety budgets: 1 MiB for snapshot, page text, extraction, evaluation, and cookies; 32 MiB for screenshots; and 64 MiB for PDFs. The service returns a typed 422 action_output_too_large response instead of truncating JSON or binary data. Retry after reducing the requested page/output scope; a 429 action_output_busy means the node's single heavy output slot is occupied and the request should be retried with backoff.

Scheduled jobs & webhooks

ab.create_job(name="price-check", url="https://shop.example/item",
              action="screenshot", interval=3600)          # hourly
ab.create_webhook("https://your-app.com/hooks",
                  events=["job.completed", "session.recording_ready"])

Webhook deliveries are HMAC-signed — verify X-AgentBrowser-Signature (sha256=<hex> over the raw body) with the secret returned on creation.

API surface

Use Session as a context manager to auto-close.

Errors raise AgentBrowserError (.status, .body, and .code when the server's error body carries a machine-readable one, e.g. action_output_too_large). 500/502 responses from gb-server and gb-noded carry a typed error envelope (see internal/platform/errenvelope.go in the main repo): in addition to .code, AgentBrowserError exposes .retryable (bool — whether the identical request is safe to retry as-is), .request_id and .session_id (correlation ids for support/log grepping), and .details (a dict with error-specific context, e.g. a debug_bundle_id). All four default to False/None for older or not-yet-converted error bodies.

Transport

GET requests (read-only, side-effect-free) automatically retry up to twice with exponential backoff on a connection failure or a 502/503/504.

Session.act() (which every action helper — click, navigate, type, login, ...— goes through) retries the same way, but only when it's provably safe: a read-only verb (extract, screenshot, read_page, ...) retries freely, exactly like a GET. Every other (write) verb retries only behind an idempotency_key — the server (P1-111) caches that action's terminal result per key, so a retried call replays the original result instead of executing again. Pass your own idempotency_key= to act() to control it yourself (e.g. to make your OWN later retry, after your process restarts, safe too); if you don't, act() generates one automatically per call so the built-in retry is never a bare, unprotected write retry.

Every other write (AgentBrowser.session(), create_webhook, create_job, delete_*, ...) is not auto-retried — those endpoints have no idempotency-key support server-side, so retrying one on a transport failure could double-create or double-delete. Session.close() keeps its own narrow, deliberate exception: a second close() call is always safe (a 404 on delete is treated as already-closed).

Pass a per-call timeout= to AgentBrowser._request/_download to override the client's default for one call.

CLI

Installing the package (pip install ./sdk/python) also installs an agentbrowser command — a deterministic way to exercise the hosted API outside an agent, reproduce a failure, or script CI checks.

agentbrowser auth set --api-key gbk_...          # stores ~/.agentbrowser/config.json (0600)
agentbrowser session create --url https://example.com --record --json
agentbrowser session act sess_123 click --param selector=#submit
agentbrowser session act sess_123 type --param selector=#user --param [email protected]
agentbrowser session status sess_123
agentbrowser session stream sess_123             # tails live NDJSON events; Ctrl-C to stop
agentbrowser session close sess_123

agentbrowser recording list
agentbrowser recording download rec_123 -o bundle.tar.gz
agentbrowser artifact list                       # recordings + as_artifact screenshots/PDFs + durable downloads
agentbrowser artifact download art_123 -o file.bin
agentbrowser job create --name price-check --url https://shop.example --action screenshot --interval 3600
agentbrowser webhook create --url https://your-app.com/hooks --events job.completed,session.recording_ready

agentbrowser doctor          # config/credentials/connectivity/api-key checks; exits 1 if unhealthy

Every command prints one JSON object to stdout: {"request_id": "...", "ok": true, "data": {...}} on success, {"request_id": "...", "ok": false, "error": "...", "error_code": "..."} on failure (exit code 1). --json gives the compact single-line form for scripts; the default is the same object pretty-printed. request_id is generated client-side per invocation for support correlation — the server doesn't (yet) echo or log it. session stream and ... download -o - are the two exceptions: a live event tail and raw downloaded bytes each print directly to stdout instead of being wrapped in the envelope, since mixing binary/streaming output with a single JSON object on the same stream would corrupt both.

Credentials resolve in order: --api-key/--base-url flags (work before or after the subcommand), AGENTBROWSER_API_KEY/AGENTBROWSER_BASE_URL env vars, then the current (or --profile-named) profile from agentbrowser auth set. agentbrowser profile list / agentbrowser profile use NAME manage multiple stored profiles.

doctor's checks are scoped to what's actually reachable with an API key (config file, credential resolution, /healthz connectivity, and an authenticated recordings:read probe) — node/infra diagnostics need operator-level auth this CLI doesn't have, and aren't attempted.

Publishing

Release steps (build/verify/twine upload) are documented internally for maintainers, not published here.