API reference

Routes, fields and errors of the browsers.openwaf.dev data plane, the management API under dash.openwaf.dev, the CLI and the MCP tools.

On this page

OpenWAF Browsers has two APIs:

  • The data plane at https://browsers.openwaf.dev, which your agent calls with a browser key (bdk_…) to start, list and stop browsers and to manage profiles.
  • The management API under https://dash.openwaf.dev/v1/orgs/{org}/browsers, which you call with an OpenWAF API token (owf_…) or the dashboard session to manage keys, settings, usage, sessions and the egress log. The CLI and the MCP tools use it.

Data plane

Base URL https://browsers.openwaf.dev. Every route needs a browser key, in either header:

X-API-Key: bdk_…
Authorization: Bearer bdk_…

JSON in and out. A key sees only the browsers it started.

Start a browser

POST /v1/browsers. Every field is optional.

FieldTypeMeaning
profilestringId or name of a profile to load. One browser uses a profile at a time.
metadataobjectUp to 10 key: value string pairs, to find the browser later (GET /v1/browsers?metadata=k=v).
keepAliveboolDo not stop on the idle timeout: the browser runs until you stop it or it reaches the maximum session length.
timeoutintegerIdle timeout in seconds: the browser stops after this long with no CDP or live view client. Default 120. Takes precedence over keepAlive.
recordingboolRecord the session as MP4. The file appears in files after the browser stops.
viewportobject{"width": 1280, "height": 800}
langstringBrowser language, for example en-US or es-ES.
webBotAuthboolSign requests with Web Bot Auth. Default: the organization's setting, true unless an admin turned it off.

The answer is the browser:

{"id": "bs_…", "status": "running",
 "cdpUrl": "wss://browsers.openwaf.dev/cdp/…",
 "cdpHttpUrl": "https://browsers.openwaf.dev/…",
 "liveUrl": "https://browsers.openwaf.dev/…",
 "urlsExpireAt": "2026-10-29T11:00:00Z", …}
  • cdpUrl is the browser-level DevTools WebSocket: chromium.connectOverCDP(cdpUrl) in Playwright, puppeteer.connect({browserWSEndpoint: cdpUrl}) in Puppeteer, npx @playwright/mcp@latest --cdp-endpoint <cdpUrl> for MCP.
  • cdpHttpUrl serves the DevTools HTTP endpoints (/json/version, /json/list, …) with their WebSocket URLs pointing back through browsers.openwaf.dev.
  • liveUrl opens the screen in a web browser, to watch or take over.
  • The tokens in these URLs expire at urlsExpireAt, 1 hour after they are issued. GET /v1/browsers/{id} returns fresh ones while the browser runs.

List and read browsers

  • GET /v1/browsers lists the key's browsers. Filters: status=running, metadata=k=v (repeatable).
  • GET /v1/browsers/{id} returns one browser, with fresh URLs while it runs.

Stop a browser

PATCH /v1/browsers/{id}
Content-Type: application/json

{"action": "stop"}

Stopping finalizes the recording and saves and unlocks the profile. A browser also stops on its own:

  • after its idle timeout (120 s by default) with no CDP or live view client;
  • when it reaches the maximum session length (60 minutes in the beta);
  • when Chrome exits;
  • when its key is rotated or revoked, or the organization runs out of quota.

Files

GET /v1/browsers/{id}/files lists the downloads and the recording of a browser, each with a signed link that expires. Session files are kept for 7 days.

Egress log

GET /v1/browsers/{id}/egress returns {"items": […]} with the latest requests the browser made through the egress proxy: time, method, host, port, decision (allow, deny or error), the reason of a denial, status and bytes. The organization-wide log is in the management API.

Profiles

A profile keeps cookies, logins and local storage between browsers.

RouteWhat it does
POST /v1/profiles {"name": "…"}Create a profile
GET /v1/profilesList profiles
GET /v1/profiles/{id or name}Read one profile
PATCH /v1/profiles/{id or name}Change it
DELETE /v1/profiles/{id or name}Delete it; 409 while a browser uses it

Data plane errors

Errors are JSON: {"error": "…", "code": "…"}.

StatuscodeWhen
400A field is invalid; error says which
401Missing, unknown, rotated or revoked key, or the key is disabled (organization over quota or not enabled)
404No such browser or profile for this key
409The profile is in use by another browser
429capacity_busyEvery browser slot of the beta is busy. Wait for Retry-After (30 seconds) and retry.
429key_concurrencyThis key already runs its maximum of browsers (2). Stop one first.
503unavailableThe service is paused for maintenance. Retry later.

A capacity_busy answer is shared capacity, not your quota: retrying after Retry-After is the right thing to do. A key_concurrency answer will not clear by waiting unless one of your browsers stops.

Management API

All routes are under https://dash.openwaf.dev/v1/orgs/{org}, with an API token (Authorization: Bearer owf_…) or the dashboard session. Reads need any role of the whole organization (readonly or higher). Keys and settings need admin. Stopping a session needs tech or higher. Writes take X-Change-Reason and are recorded in the audit log; they are not versioned configuration and do not take dry_run.

RouteWhat it does
GET /browsersOverview: status, quota, settings, usage of the month, capacity and access requirements. Readable before access is approved.
PATCH /browsers/settingsChange egress_mode, allow and web_bot_auth (any subset); answers the overview
GET /browsers/keysList keys
POST /browsers/keysCreate a key: {"name": "ci-agent"}; answers 201 {"key", "secret"}
POST /browsers/keys/{id}/rotateNew secret: {"key", "secret"}. The old secret stops at once and its live browsers end.
DELETE /browsers/keys/{id}Revoke a key (204); its live browsers end
GET /browsers/usageUsage series, per key and totals
GET /browsers/sessionsBrowsers of the organization; ?status=running
POST /browsers/sessions/{id}/stopStop a browser; answers the session
GET /browsers/egressEgress log of the organization

Overview

{"enabled": true, "status": "enabled", "available": true,
 "api_url": "https://browsers.openwaf.dev", "plan": "beta",
 "quota": {"browser_hours": 20, "egress_gb": 5, "concurrency": 2, "max_session_minutes": 60, "max_keys": 5},
 "settings": {"egress_mode": "open", "allow": [], "web_bot_auth": true},
 "period": {"start": "2026-10-01T00:00:00Z", "end": "2026-11-01T00:00:00Z"},
 "usage": {"browser_seconds": 4310, "egress_bytes": 123456789, "sessions": 31, "denied_requests": 4},
 "usage_updated_at": "2026-10-29T12:01:00Z",
 "warning": false,
 "capacity": {"max_sessions": 5, "running": 2, "busy": false},
 "requirements": {"owners_email_verified": true, "owners_two_factor": true}}
  • status is enabled, not_enabled or quota_exceeded.
  • warning is true when browser-hours or egress reach 80 % of the quota.
  • capacity is the shared capacity of the service, or null when it is not known.
  • requirements says whether every owner and admin has a verified email and two-factor authentication, which approval needs.

Settings

{"egress_mode": "allowlist", "allow": ["example.com", "*.example.com"], "web_bot_auth": true}
FieldValues
egress_modeopen: any public host (the default). allowlist: only the hosts in allow. Private and special-purpose addresses are refused in both modes.
allowUp to 100 entries. example.com is that host only; *.example.com its subdomains.
web_bot_authDefault for new browsers. A browser can still set webBotAuth either way.

Keys

{"id": "6f1c…", "name": "ci-agent", "prefix": "bdk_AbC1", "disabled": false,
 "created_at": "2026-10-29T10:00:00Z", "created_by": "…", "rotated_at": null}

The name matches ^[a-z0-9][a-z0-9-]{0,62}$ and is unique in the organization. disabled is true while the organization is over quota or not enabled. The secret of a create or rotate answer is shown once, with Cache-Control: no-store.

Usage

GET /browsers/usage?from=RFC3339&to=RFC3339&step=day|hour. Without parameters: the current month, by day.

{"from": "…", "to": "…", "step": "day",
 "series": [{"t": "2026-10-29T00:00:00Z", "browser_seconds": 1800, "egress_bytes": 52428800, "sessions": 6, "denied_requests": 1}],
 "by_key": [{"key_id": "6f1c…", "name": "ci-agent", "browser_seconds": 1800, "egress_bytes": 52428800, "sessions": 6, "denied_requests": 1}],
 "totals": {"browser_seconds": 1800, "egress_bytes": 52428800, "sessions": 6, "denied_requests": 1},
 "quota": {…}, "period": {"start": "…", "end": "…"}, "usage": {…}}

usage is the month to date, the figure the quota is checked against. Usage is collected every minute, so the numbers lag by up to about two minutes.

Sessions

GET /browsers/sessions?status=running:

{"items": [{"id": "bs_…", "key_id": "6f1c…", "key_name": "ci-agent", "status": "running",
            "created_at": "…", "started_at": "…", "stopped_at": null, "stop_reason": null,
            "live_url": "https://browsers.openwaf.dev/…", "metadata": {"task": "quickstart"}}]}

status is running, idle or stopped. live_url is a signed, view-only link, present only while the browser runs, valid for 1 hour.

Egress log

GET /browsers/egress?key=<id>&since=RFC3339&decision=deny&limit=200. Newest first; limit up to 1000, default 200.

{"items": [{"ts": "…", "key_id": "6f1c…", "key_name": "ci-agent", "session": "bs_…",
            "method": "CONNECT", "host": "example.com", "port": 443, "decision": "allow", "reason": "",
            "status": 200, "bytes_up": 1830, "bytes_down": 48211, "ms": 412}]}

decision is allow, deny or error; reason says why a request was denied.

Management API errors

StatuscodeWhen
403feature_disabledOpenWAF Browsers is not enabled for the organization
403forbiddenThe role is too low, or the member or token is limited to a client or a zone
404not_foundNo such key or session in the organization
409conflictA key with that name already exists
409key_limitThe organization already has its maximum of keys (5 by default); revoke one first
422invalidA field breaks the rules above; field names it
503unavailableThe browser service cannot be reached right now

Operator access

Approval is an operator action, not a customer route: an operator turns OpenWAF Browsers on for the organization with a reason and, if needed, a different quota. It fails while an owner or admin lacks a verified email or two-factor authentication. To ask for it, see get access.

CLI

openwaf-cloud ctl browsers … calls the management API. Every change takes --reason "…", shows what it will do and asks before applying it. --yes applies without asking (required without a terminal, as in CI); --dry-run only shows it. Reads take --json for the raw API answer. See get started with the CLI and changes.

CommandWhat it does
browsers statusThe overview: approval, usage of the month against the quota, per-key limits, settings and shared capacity
browsers settings [--egress-mode open|allowlist] [--allow a.example,*.example] [--web-bot-auth on|off] --reason "…" [--yes]Change the settings (admin). --allow replaces the whole list; empty means none. Without options it shows the overview.
browsers keys [list]Keys, with prefix and state
browsers keys create <name> --reason "…" [--yes]Create a key (admin); the secret is shown once
browsers keys rotate <key> --reason "…" [--yes]New secret (admin); the current one stops at once. <key> is the name or the id.
browsers keys revoke <key> --reason "…" [--yes]Revoke a key (admin)
browsers usage [--from RFC3339] [--to RFC3339] [--step day|hour]Usage by day or hour and per key. --from defaults to the 1st of this month.
browsers sessions [--status running|idle|stopped]Browsers of the organization
browsers sessions stop <id> --reason "…" [--yes]Stop a browser (tech)
browsers egress [--key <key>] [--since 1h|24h|7d|RFC3339] [--deny] [--limit N]Requests of the browsers through the egress proxy. --deny keeps only denied ones; --limit defaults to 200, up to 1000.

MCP tools

The OpenWAF MCP server has 10 tools for OpenWAF Browsers. Writes need a reason and follow the two steps of the other non-versioned tools: confirm=false only checks, confirm=true applies, without expected_version.

ToolArgumentsRole
browser_statusreadonly
browser_settingsnone to read; egress_mode, allow, web_bot_auth, reason, confirm to changeadmin to change
browser_keys_listreadonly
browser_keys_createname, reason, confirm; the secret is returned onceadmin
browser_keys_rotatekey, reason, confirmadmin
browser_keys_revokekey, reason, confirmadmin
browser_sessions_liststatusreadonly
browser_sessions_stopsession, reason, confirmtech
browser_usagefrom, to, stepreadonly
browser_egress_eventskey, since, decision, limitreadonly

The MCP tools manage the organization. To drive a browser from an assistant, use the Playwright MCP server with the browser's cdpUrl, as in the quickstart.

Last updated:

↑↓ to navigate↵ to openesc to close