Browser automation API

One browser.
Four ways to drive it.

Create a persistent WebBrain browser, watch it work in noVNC, and control that same visible session from REST, Node.js, Python, or PHP.

Base URLhttps://webbrain.cloud
1CreateLaunch an isolated browser.
2ReadyWait for the extension bridge.
3RunSend a natural-language task.
4ResultPoll for text or structured JSON.
export WEBBRAIN_API_KEY='wbp_your_key_here'

# 1. Create a browser
SESSION_ID=$(curl -sS -X POST https://webbrain.cloud/api/browser-sessions \
  -H "Authorization: Bearer $WEBBRAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"normal"}' | jq -r '.browser_session.id')

# 2. Wait for the extension bridge
until [ "$(curl -sS \
  "https://webbrain.cloud/api/browser-sessions/$SESSION_ID" \
  -H "Authorization: Bearer $WEBBRAIN_API_KEY" \
  | jq -r '.browser_session.runtime_ready')" = "true" ]; do sleep 2; done

# 3. Start a visible run
RUN_ID=$(curl -sS -X POST \
  "https://webbrain.cloud/api/browser-sessions/$SESSION_ID/runs" \
  -H "Authorization: Bearer $WEBBRAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"task":"Open google.com and return the page title"}' \
  | jq -r '.run_id')

# 4. Read the result
curl -sS \
  "https://webbrain.cloud/api/browser-sessions/$SESSION_ID/runs/$RUN_ID" \
  -H "Authorization: Bearer $WEBBRAIN_API_KEY" | jq

Start here

Authenticate once

Create a key from the dashboard's API Keys panel and send it as Authorization: Bearer wbp_…. A key can control only its owner's browser sessions. The complete secret is displayed once, so revoke it immediately if it is exposed.

Lifecycle

Browser sessions

normal sessions keep Chrome on a fixed private profile volume and can be paused after shared Downloads storage is configured. incognito sessions use the dashboard's always-on browser mode: Chrome and Downloads stay on one running Droplet and Pause is unavailable. Both remain until explicitly destroyed. Poll until runtime_ready is true before starting runs.

POST /api/browser-sessions request body

An empty JSON object is valid and creates a normal browser. Infrastructure placement, Droplet size, proxy credentials, and the reserved WebBrain Cloud connection are private server configuration and cannot be overridden by this request.

FieldTypeDefaultApplies toPurpose
display_namestringNoneBothAn optional dashboard label up to 120 characters.
typestring enumnormalBothnormal or incognito, matching the dashboard.
proxy_enabledbooleanServer defaultBothtrue uses the server-configured proxy; false uses a direct connection.
proxy_countrystringrotateBothOptional country or region code (e.g. us, de) passed when proxy_enabled is true. Substituted into % template placeholders in server proxy URLs, falling back to rotate if omitted or unconfigured.
webbrain_configwebbrain-config/1 objectNoneBothOptional sparse Settings import copied directly from WebBrain's /export --config output.

DigitalOcean region and size come only from DO_REGION and DO_SIZE. Proxy routing and credentials come only from the server's proxy environment. They are intentionally absent from the public request body.

Import WebBrain Settings at creation

Paste the complete JSON produced by WebBrain's /export --config command into webbrain_config. The export metadata is accepted unchanged. Settings are sparse: omitted fields keep their normal WebBrain or cloud defaults, accepted fields are applied before runtime_ready, and invalid or managed fields are ignored without failing browser creation.

Editable fields are wbLocale, themeMode, verboseMode, selectionShortcutEnabled, helpImproveWebBrain, voiceInputEnabled, notifySound, completionConfetti, providerFilter, screenshotFallback, autoScreenshot, useSiteAdapters, apiMutationObserverEnabled, screenshotRedaction, the agent/cost limits, captchaSolverEnabled, capsolverApiKey, providers, and activeProvider.

WebBrain Cloud connection fields, plan/review policy, tracing, permissions, Downloads path, local-network access, schedules, profile, memory, and custom skills remain platform-managed. Additional providers are merged, but private/local endpoints are ignored and the reserved webbrain_cloud connection always keeps its platform-issued URL, model, and session token. A valid configured external provider may be selected with activeProvider.

Config exports contain plaintext provider and CapSolver API keys. Send them only over HTTPS, never log the request body, and remember that normal browsers retain accepted settings on their profile volume while incognito settings disappear when the browser is destroyed.

<?php

require_once __DIR__ . '/clients/php/WebBrainClient.php';

$client = new WebBrainClient(getenv('WEBBRAIN_API_KEY') ?: '');

// Replace this whole NOWDOC body with WebBrain's /export --config output.
$webbrainConfigJson = <<<'JSON'
{
  "schema": "webbrain-config/1",
  "exportedAt": "2026-07-19T10:00:00.000Z",
  "webbrainVersion": "7.3.0",
  "warning": "Contains plaintext provider API keys and other sensitive Settings data. Store securely.",
  "settings": {
    "captchaSolverEnabled": true,
    "capsolverApiKey": "replace-with-your-key",
    "activeProvider": "webbrain_cloud"
  }
}
JSON;

$session = $client->createBrowserSession([
    'type' => 'incognito',
    'webbrain_config' => json_decode(
        $webbrainConfigJson,
        true,
        512,
        JSON_THROW_ON_ERROR,
    ),
]);

print_r($session['webbrain_config_result'] ?? []);

Config import result

When webbrain_config is supplied, the create response includes accepted field paths, ignored fields with stable reason codes, and non-secret warnings. Values and credentials are never echoed.

{
  "browser_session": {
    "id": "bs_example",
    "status": "provisioning"
  },
  "webbrain_config_result": {
    "accepted": [
      "settings.captchaSolverEnabled",
      "settings.capsolverApiKey",
      "settings.activeProvider"
    ],
    "ignored": [
      {
        "field": "settings.planBeforeActMode",
        "reason": "platform_managed"
      }
    ],
    "warnings": []
  }
}
POST/api/browser-sessionsCreate a normal or incognito browser.
GET/api/browser-sessionsList your sessions.
GET/api/browser-sessions/:sessionIdRead readiness.
PATCH/api/browser-sessions/:sessionIdSet its display name.
GET/api/browser-sessions/:sessionId/proxyRead proxy and exit IP.
PATCH/api/browser-sessions/:sessionId/proxyEnable or disable the server-configured proxy without restart.
DELETE/api/browser-sessions/:sessionId/proxyReturn to a direct connection.
POST/api/browser-sessions/:sessionId/resetRestart the running browser.
POST/api/browser-sessions/:sessionId/pauseStop the Droplet and retain the profile.
POST/api/browser-sessions/:sessionId/resumeAttach the profile to a new Droplet.
DELETE/api/browser-sessions/:sessionIdDestroy the browser and its infrastructure.
POST/api/browser-sessions/:sessionId/connect-tokenCreate a noVNC link.
POST/api/browser-sessions/:sessionId/downloads-accessCreate private Downloads credentials.

Copy and adapt

Create and run in your language

These examples create a named normal browser with a direct connection, wait until its runtime is ready, run one visible task, and print the result. The bundled clients have no third-party runtime dependencies.

import { WebBrainClient } from './clients/node/webbrain-client.js';

const client = new WebBrainClient({
  apiKey: process.env.WEBBRAIN_API_KEY,
});

const session = await client.createBrowserSession({
  display_name: 'Research browser',
  type: 'normal',
  proxy_enabled: false,
});

const ready = await client.waitForBrowserSession(session.id);
const run = await client.createRun(ready.id, {
  task: 'Open example.com and return the page title',
});
const finished = await client.waitForRun(ready.id, run.run_id);

console.log(finished.result);

File transfer

Upload and download files

For a ready or paused browser, request access metadata from POST /api/browser-sessions/:sessionId/downloads-access. The response contains an HTTPS url, username, password, upload_limit_bytes, and expires_at. It is returned with Cache-Control: no-store; do not log it.

# Obtain access and keep the secret out of the literal shell history
DOWNLOADS_ACCESS=$(curl --fail-with-body -sS -X POST "https://webbrain.cloud/api/browser-sessions/$SESSION_ID/downloads-access" -H "Authorization: Bearer $WEBBRAIN_API_KEY" -H "Content-Type: application/json" -d '{}')
DOWNLOADS_URL=$(printf '%s' "$DOWNLOADS_ACCESS" | jq -r '.url')
DOWNLOADS_USER=$(printf '%s' "$DOWNLOADS_ACCESS" | jq -r '.username')
DOWNLOADS_PASSWORD=$(printf '%s' "$DOWNLOADS_ACCESS" | jq -r '.password')

# Machine-readable listing
curl --fail-with-body -sS -u "$DOWNLOADS_USER:$DOWNLOADS_PASSWORD" -H 'Accept: application/json' "$DOWNLOADS_URL" | jq

# Browser-local streaming upload; response.browser_path is immediately usable
LOCAL_FILE='./report.pdf'
REMOTE_NAME=$(jq -rn --arg name "$(basename -- "$LOCAL_FILE")" '$name | @uri')
curl --fail-with-body -sS -X PUT -u "$DOWNLOADS_USER:$DOWNLOADS_PASSWORD" -H 'Content-Type: application/octet-stream' -H 'X-WebBrain-Upload-Target: browser' --upload-file "$LOCAL_FILE" "${DOWNLOADS_URL}${REMOTE_NAME}" | jq

# Full download and a byte-range download
curl --fail-with-body -sS -u "$DOWNLOADS_USER:$DOWNLOADS_PASSWORD" --output './report.pdf' "${DOWNLOADS_URL}${REMOTE_NAME}"
curl --fail-with-body -sS -u "$DOWNLOADS_USER:$DOWNLOADS_PASSWORD" -H 'Range: bytes=0-1023' --output './report.first-1KiB' "${DOWNLOADS_URL}${REMOTE_NAME}"

Upload response

A successful PUT returns the final collision-safe filename, byte size, SHA-256 digest, storage backend, and whether the file is already available at an absolute path inside the cloud browser.

{
  "name": "github-avatar-test.jpg",
  "size": 38564,
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "storage_backend": "browser_local",
  "browser_path": "/root/Downloads/github-avatar-test.jpg",
  "browser_ready": true
}
FieldTypeMeaning
namestringFinal filename after any collision suffix is applied.
sizenumberStored byte count.
sha256stringLowercase SHA-256 hex digest of the uploaded content.
storage_backendstringbrowser_local or shared_object.
browser_pathstring or nullAbsolute browser-visible filesystem path when locally materialized; otherwise null.
browser_readybooleantrue only when the browser can open browser_path immediately.

Incognito uploads are browser-local. For a ready, running normal browser, send X-WebBrain-Upload-Target: browser on the PUT to upload directly to that browser and receive its real absolute Downloads path with browser_ready: true. The request returns 409 Conflict while the browser is paused or not ready. Without the header, normal uploads use shared storage, remain available while paused, and return storage_backend: "shared_object", browser_path: null, and browser_ready: false. Existing path, url, etag, and idempotent fields may also be present for compatibility and shared-storage bookkeeping.

For normal browsers, shared Downloads are scoped to the user, remain online while Droplets are paused, and have a default 25 GiB fair-use allowance per user. Directory requests return the file tray by default and JSON when sent Accept: application/json. Files support GET, HEAD, one HTTP byte range, and raw streaming PUT uploads. Existing names receive a numbered suffix. Delete, rename, and folder creation are not available.

Chrome writes downloads to temporary Droplet staging. After Chrome reports completion, WebBrain uploads the file to shared storage and removes the local copy only after confirmation. Pause is refused while staging or sync work remains.

Client helpers

Node.js and PHP expose listDownloads, uploadDownloadsFile, and downloadDownloadsFile. Python exposes list_downloads, upload_downloads_file, and download_downloads_file. Set browserLocal: true in Node.js, browser_local=True in Python, or the PHP upload helper's final argument to true for a browser-local upload. All transfer file bodies as streams and protect existing local files unless overwrite is explicitly enabled.

Automation

Run a task

Runs are asynchronous by default and return 202 Accepted with a run_id. Poll the run endpoint, or set wait: true to wait until completion or until WebBrain needs user input.

FieldRequiredPurpose
taskOne ofThe natural-language browser task. Supply exactly one of task and workflow_id.
workflow_idOne ofAn owned saved workflow to replay.
parametersWorkflow onlyTransient string values keyed by declared parameter ID.
waitNoWait for a terminal response instead of returning immediately.
timeout_msNoMaximum time for the blocking request path.
tab_idNoTarget a specific tab. Otherwise the visible active page is used.
output_schemaNoRequire a validated JSON result.
POST/api/browser-sessions/:sessionId/runsStart a run.
GET/api/browser-sessions/:sessionId/runs/:runIdRead a run.
POST/api/browser-sessions/:sessionId/runs/:runId/messagesAppend a turn after the run finishes.
POST/api/browser-sessions/:sessionId/runs/:runId/responsesAnswer its pending clarify_id.
POST/api/browser-sessions/:sessionId/runs/:runId/abortAbort a run.

Post a new task to /messages after a run is completed, failed, or aborted. WebBrain creates an immutable child run with parent_run_id and reuses the same tab and conversation, so the follow-up can continue on the current page or navigate elsewhere. Append later turns to the newest child. Use /responses only for a paused needs_user_input run.

Repeat safely

Compile and replay saved workflows

Create a workflow from a completed successful cloud run with POST /api/workflows, or import the raw sanitized webbrain-workflow/1 JSON definition with POST /api/workflows/import. Portable files are limited to 1 MiB, never contain runtime parameter values, and receive a fresh cloud ID and timestamps.

POST/api/workflowsCompile and store an exact successful run trace.
POST/api/workflows/importValidate and store a portable workflow definition.
GET/api/workflows?limit=&offset=List workflow metadata.
GET/api/workflows/:workflowIdRead metadata and the sanitized definition.
GET/api/workflows/:workflowId/exportDownload the raw portable workflow JSON.
PATCH/api/workflows/:workflowIdRename a workflow.
DELETE/api/workflows/:workflowIdDelete the definition while retaining historical runs.

Before replay, open a page matching the workflow's start URL family in a compatible login/profile. Start it with workflow_id and parameters; output_schema is not supported for workflow runs in v1. Parameter values are validated before dispatch and are never stored or returned. A pre-upgrade runtime returns 409 for workflow operations but remains usable for ordinary tasks.

Typed results

Structured output

Use shorthand fields such as string, number, boolean, string[], and optional string?. The supported JSON Schema subset includes type, properties, required, items, enum, and additionalProperties.

Run state

Know when it is done

A needs_user_input response includes pending_input.clarify_id; post that ID and an answer to the responses endpoint to resume. A terminal response includes result, summary, final_url, and any failure detail in error.

runningneeds_user_inputcompletedfailedabortingaborted

Open Agent Skill

Give your agent a cloud browser

The website publishes a portable webbrain-cloud skill for Codex, OpenClaw, Claude Code, and Claude chat or Cowork. It teaches the agent session selection, readiness polling, run continuations, clarification handling, file transfer, cleanup, and the security boundaries around browser actions.

Install the skill, then provide WEBBRAIN_API_KEY through the agent runtime's environment or secret manager. Do not put the key inside SKILL.md, its ZIP, a prompt, or a tracked file. The runtime also needs Node.js 18+ and outbound HTTPS access to webbrain.cloud.

git clone --depth 1 https://github.com/esokullu/webbrain-platform.git
mkdir -p "$HOME/.agents/skills"
cp -R webbrain-platform/.agents/skills/webbrain-cloud "$HOME/.agents/skills/"

Codex and OpenClaw both discover the checked-in .agents/skills location when working directly in this repository. Claude chat and Cowork accept the packaged skill from Customize → Skills; code execution and network access must be enabled.

No dependencies

Use your language

The repository includes small clients with the same core operations: session creation, pause and resume, readiness, runs, follow-up turns, polling, aborting, structured output, noVNC links, and streaming private Downloads transfers.