API reference
BrowserThing provides a REST control plane and WebSocket connections for
Playwright. The examples use a local server. Add
-H "Authorization: Bearer $BROWSERTHING_API_KEY" to REST requests after you
enable authentication.
The full request and response schemas are in the v0.6.0 OpenAPI document. WebSocket routes are documented separately below.
Capacity and workers
Section titled “Capacity and workers”| Method and path | Purpose |
|---|---|
GET /v1/capacity |
Read browser capacity, free slots, and queue depth. |
GET /v1/workers |
List worker records. |
GET /healthz |
Check process health without authentication. |
GET /readyz |
Check database readiness without authentication. |
curl -fsS http://localhost:8080/v1/capacitycurl -fsS http://localhost:8080/v1/workersFor one idle Chromium worker with five slots, GET /v1/capacity returns
200 OK with these values:
{ "browsers": [ { "browser": "chromium", "workers": 1, "max_slots": 5, "active_sessions": 0, "available_slots": 5 } ], "totals": { "workers": 1, "max_slots": 5, "active_sessions": 0, "available_slots": 5 }, "queued": 0, "max_queue_size": 100}The queued capacity value belongs to the server replica that handles the
request. It is not a sum across replicas.
Create and attach a session
Section titled “Create and attach a session”POST /v1/sessions reserves a session. Supply the browser type and the client’s
Playwright version so the server can select a matching worker:
curl -fsS http://localhost:8080/v1/sessions \ -H 'Content-Type: application/json' \ -d '{"browser":"chromium","playwright_version":"1.63.0"}'Success returns 201 Created and a session object. These are selected fields
from an example response; IDs differ for each session:
{ "id": "6fb174a2-4dc3-4c29-a33c-20f3b05da4bd", "browser": "chromium", "playwright_version": "1.63.0", "mode": "default", "status": "pending", "started_at": null, "connect_metadata": {}}Attach before the pending session expires (30 seconds by default). This complete example creates the session and uses its returned ID immediately. It needs Node.js 20 or later and the matching client:
npm install playwright@1.63.0Save this as create-session.mjs. Set BROWSERTHING_URL for a remote server and
BROWSERTHING_API_KEY if authentication is enabled. The key is used for both the
REST request and the WebSocket connection.
import { chromium } from 'playwright';
const server = process.env.BROWSERTHING_URL || 'http://localhost:8080';const key = process.env.BROWSERTHING_API_KEY;const headers = key ? { Authorization: `Bearer ${key}` } : {};
const response = await fetch(new URL('/v1/sessions', server), { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json' }, body: JSON.stringify({ browser: 'chromium', playwright_version: '1.63.0' }),});if (!response.ok) { throw new Error(`Create session: HTTP ${response.status}: ${await response.text()}`);}
const session = await response.json();const endpoint = new URL(`/sessions/${session.id}`, server);endpoint.protocol = endpoint.protocol === 'https:' ? 'wss:' : 'ws:';
const browser = await chromium.connect(endpoint.href, { headers });try { const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://example.com'); await page.screenshot({ path: 'preview.png', fullPage: true });} finally { await browser.close();}Run node create-session.mjs. It saves preview.png on the client machine.
This attaches to a pending session. It does not resume a session after its connection has closed. The connecting client’s major and minor version must match the session’s worker.
Inspect or terminate a session
Section titled “Inspect or terminate a session”| Method and path | Purpose |
|---|---|
POST /v1/sessions |
Create a pending session. |
GET /v1/sessions/{id} |
Read one session record. |
DELETE /v1/sessions/{id} |
Complete a pending or running session. |
curl -fsS http://localhost:8080/v1/sessions/SESSION_IDcurl -fsS -X DELETE http://localhost:8080/v1/sessions/SESSION_IDGET returns 200 OK with the session object. A successful DELETE returns
204 No Content with no response body. An unknown ID returns 404 Not Found.
For a running session, the relay notices deletion on its next heartbeat and
closes both WebSocket peers with code 1001. The normal delay is at most one
SESSION_HEARTBEAT_INTERVAL (10 seconds by default).
WebSocket routes
Section titled “WebSocket routes”GET /?browser=chromium -> create session -> select worker -> relay Playwright traffic
GET /sessions/{id} -> attach to pending session -> relay Playwright trafficBoth routes accept Authorization: Bearer pwd_... or ?token=pwd_.... The first
route uses DEFAULT_BROWSER_TYPE when browser is omitted. Supported browser
types are chromium, firefox, and webkit.
The relay forwards User-Agent and x-playwright-* headers to workers, plus
its own x-pwd-session-id. It does not forward client authorization, cookies,
or query tokens to the worker.
Error responses
Section titled “Error responses”REST errors include an HTTP status and a JSON body with details. For example,
requesting mode: dedicated returns 422 Unprocessable Entity with these fields:
{ "title": "Unprocessable Entity", "status": 422, "detail": "dedicated mode is not available yet"}Use curl -sS -i to see both the status and error body. curl -f hides the body
on errors. Failed WebSocket connections return their error before the upgrade;
their JSON bodies contain a message field. See HTTP errors
for causes and next actions.
API keys
Section titled “API keys”Manage keys with the server CLI:
docker compose exec server server apikey create --name clientdocker compose exec server server apikey listdocker compose exec server server apikey revoke --id KEY_IDAll valid keys have full access in v0.6.0. Worker registration and lifecycle
routes under /internal/workers are for the worker protocol; their schemas are
also included in OpenAPI.