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.
| Field | Type | Default | Applies to | Purpose |
|---|---|---|---|---|
display_name | string | None | Both | An optional dashboard label up to 120 characters. |
type | string enum | normal | Both | normal or incognito, matching the dashboard. |
proxy_enabled | boolean | Server default | Both | true uses the server-configured proxy; false uses a direct connection. |
proxy_country | string | rotate | Both | Optional 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_config | webbrain-config/1 object | None | Both | Optional 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": []
}
}
/api/browser-sessionsCreate a normal or incognito browser./api/browser-sessionsList your sessions./api/browser-sessions/:sessionIdRead readiness./api/browser-sessions/:sessionIdSet its display name./api/browser-sessions/:sessionId/proxyRead proxy and exit IP./api/browser-sessions/:sessionId/proxyEnable or disable the server-configured proxy without restart./api/browser-sessions/:sessionId/proxyReturn to a direct connection./api/browser-sessions/:sessionId/resetRestart the running browser./api/browser-sessions/:sessionId/pauseStop the Droplet and retain the profile./api/browser-sessions/:sessionId/resumeAttach the profile to a new Droplet./api/browser-sessions/:sessionIdDestroy the browser and its infrastructure./api/browser-sessions/:sessionId/connect-tokenCreate a noVNC link./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);
import os
from clients.python.webbrain_client import WebBrainClient
client = WebBrainClient(os.environ["WEBBRAIN_API_KEY"])
session = client.create_browser_session(
display_name="Research browser",
type="normal",
proxy_enabled=False,
)
ready = client.wait_for_browser_session(session["id"])
run = client.create_run(
ready["id"],
"Open example.com and return the page title",
)
finished = client.wait_for_run(ready["id"], run["run_id"])
print(finished["result"])
<?php
require_once __DIR__ . '/clients/php/WebBrainClient.php';
$client = new WebBrainClient(getenv('WEBBRAIN_API_KEY') ?: '');
$session = $client->createBrowserSession([
'display_name' => 'Research browser',
'type' => 'normal',
'proxy_enabled' => false,
]);
$ready = $client->waitForBrowserSession($session['id']);
$run = $client->createRun(
$ready['id'],
'Open example.com and return the page title',
);
$finished = $client->waitForRun($ready['id'], $run['run_id']);
print_r($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
}
| Field | Type | Meaning |
|---|---|---|
name | string | Final filename after any collision suffix is applied. |
size | number | Stored byte count. |
sha256 | string | Lowercase SHA-256 hex digest of the uploaded content. |
storage_backend | string | browser_local or shared_object. |
browser_path | string or null | Absolute browser-visible filesystem path when locally materialized; otherwise null. |
browser_ready | boolean | true 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.
| Field | Required | Purpose |
|---|---|---|
task | One of | The natural-language browser task. Supply exactly one of task and workflow_id. |
workflow_id | One of | An owned saved workflow to replay. |
parameters | Workflow only | Transient string values keyed by declared parameter ID. |
wait | No | Wait for a terminal response instead of returning immediately. |
timeout_ms | No | Maximum time for the blocking request path. |
tab_id | No | Target a specific tab. Otherwise the visible active page is used. |
output_schema | No | Require a validated JSON result. |
/api/browser-sessions/:sessionId/runsStart a run./api/browser-sessions/:sessionId/runs/:runIdRead a run./api/browser-sessions/:sessionId/runs/:runId/messagesAppend a turn after the run finishes./api/browser-sessions/:sessionId/runs/:runId/responsesAnswer its pending clarify_id./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.
/api/workflowsCompile and store an exact successful run trace./api/workflows/importValidate and store a portable workflow definition./api/workflows?limit=&offset=List workflow metadata./api/workflows/:workflowIdRead metadata and the sanitized definition./api/workflows/:workflowId/exportDownload the raw portable workflow JSON./api/workflows/:workflowIdRename a workflow./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.
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/"
git clone --depth 1 https://github.com/esokullu/webbrain-platform.git
openclaw skills install \
./webbrain-platform/.agents/skills/webbrain-cloud \
--as webbrain-cloud --global
git clone --depth 1 https://github.com/esokullu/webbrain-platform.git
# Claude Code
mkdir -p "$HOME/.claude/skills"
cp -R webbrain-platform/.agents/skills/webbrain-cloud "$HOME/.claude/skills/"
# Claude chat or Cowork: upload the resulting ZIP in Customize > Skills
(cd webbrain-platform/.agents/skills && zip -r webbrain-cloud.zip webbrain-cloud)
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.