Skip to main content
Use the REST API when your platform owns orchestration over HTTP or when another language controls the workflow. The Python package is currently a stub. Python services should call the REST API directly until the Python SDK ships the TypeScript SDK surface.

Authentication

curl https://api.webcompute.dev/v1/browsers \
  -H "Authorization: Bearer $WEBCOMPUTE_API_KEY"
/health is public. Browser, file, download, recording, and execution endpoints require authentication.

Minimal lifecycle

The shell example uses jq to extract the browser ID from the create response. Browser lifecycle create and delete requests require an Idempotency-Key header. Create a browser:
BROWSER_JSON=$(curl -sS -X POST https://api.webcompute.dev/v1/browsers \
  -H "Authorization: Bearer $WEBCOMPUTE_API_KEY" \
  -H "Idempotency-Key: browser-create-$(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"recording":true,"policy":{"allowedDomains":["example.com"]}}')
Run Playwright code against it:
BROWSER_ID=$(printf '%s' "$BROWSER_JSON" | jq -r '.id // .browser.id')

curl -sS -X POST "https://api.webcompute.dev/v1/browsers/$BROWSER_ID/playwright/execute" \
  -H "Authorization: Bearer $WEBCOMPUTE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "await page.goto(\"https://example.com\"); return { title: await page.title(), url: page.url() };",
    "capture": { "status": true, "observation": { "kind": "aria", "includeOn": "always" } }
  }'
Clean up:
curl -sS -X DELETE "https://api.webcompute.dev/v1/browsers/$BROWSER_ID" \
  -H "Authorization: Bearer $WEBCOMPUTE_API_KEY" \
  -H "Idempotency-Key: browser-close-$(uuidgen)"
The API reference covers status, browser execution, files, downloads, dialogs, permissions, recordings, screenshots, PDFs, proxy fields, and cleanup.

Python over HTTP

import json
import os
import uuid
import urllib.request

API_KEY = os.environ["WEBCOMPUTE_API_KEY"]
BASE_URL = "https://api.webcompute.dev"


def request(method, path, body=None, idempotency_key=None):
    data = None if body is None else json.dumps(body).encode("utf-8")
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    }
    if idempotency_key:
        headers["Idempotency-Key"] = idempotency_key
    req = urllib.request.Request(
        f"{BASE_URL}{path}",
        data=data,
        method=method,
        headers=headers,
    )
    with urllib.request.urlopen(req, timeout=60) as response:
        payload = response.read()
        return json.loads(payload) if payload else None


created = request("POST", "/v1/browsers", {
    "recording": True,
    "policy": {"allowedDomains": ["example.com"]},
}, idempotency_key=f"browser-create-{uuid.uuid4()}")
browser_id = created.get("id") or created["browser"]["id"]

try:
    result = request("POST", f"/v1/browsers/{browser_id}/playwright/execute", {
        "code": "await page.goto('https://example.com'); return await page.title();",
        "capture": {"status": True, "observation": {"kind": "aria", "includeOn": "always"}},
    })
    print(result["result"])
finally:
    request("DELETE", f"/v1/browsers/{browser_id}", idempotency_key=f"browser-close-{uuid.uuid4()}")

When to prefer the SDK

Use the TypeScript SDK when your app is written in TypeScript and can call web.agent() directly. Use REST when the integration boundary is HTTP. Reference: API reference, TypeScript SDK reference, proxy reference, and policy reference.