Skip to content

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.

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.
Terminal window
curl -fsS http://localhost:8080/v1/capacity
curl -fsS http://localhost:8080/v1/workers

For 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.

POST /v1/sessions reserves a session. Supply the browser type and the client’s Playwright version so the server can select a matching worker:

Terminal window
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:

Terminal window
npm install playwright@1.63.0

Save 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.

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.
Terminal window
curl -fsS http://localhost:8080/v1/sessions/SESSION_ID
curl -fsS -X DELETE http://localhost:8080/v1/sessions/SESSION_ID

GET 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).

GET /?browser=chromium
-> create session -> select worker -> relay Playwright traffic
GET /sessions/{id}
-> attach to pending session -> relay Playwright traffic

Both 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.

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.

Manage keys with the server CLI:

Terminal window
docker compose exec server server apikey create --name client
docker compose exec server server apikey list
docker compose exec server server apikey revoke --id KEY_ID

All 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.