Move a Browserbase session workload to WebX
WebX exposes a Browserbase-shaped session data plane under /v1. The goal is
to make evaluation reversible: keep Playwright/Puppeteer and the familiar
session lifecycle, change the API base URL, then opt into WebX's verified
execution features when they are useful.
What is compatible
| Browserbase contract | WebX |
|---|---|
X-BB-API-Key | Accepted alongside x-api-key and Bearer auth |
POST /v1/sessions | Creates an isolated Chromium process and returns connectUrl |
GET /v1/sessions | Lists tenant-scoped sessions |
GET /v1/sessions/:id | Returns Browserbase-style lifecycle metadata |
POST /v1/sessions/:id with REQUEST_RELEASE | Releases the browser |
GET /v1/sessions/:id/debug | Returns an interactive signed live-view URL |
GET /v1/sessions/:id/logs | Returns captured CDP/network/console/audit events |
GET /v1/sessions/:id/recording | Returns captured JPEG replay events |
The response also includes a webx object with receipt, execution-receipt,
replay, live-view, and webx why links. Existing clients ignore this additive
field; trust-aware clients can use it immediately.
Playwright example
import { chromium } from "playwright-core";
const api = "https://webx.agentslab.host";
const response = await fetch(`${api}/v1/sessions`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-bb-api-key": process.env.WEBX_API_KEY!,
},
body: JSON.stringify({
timeout: 300,
keepAlive: false,
browserSettings: { viewport: { width: 1440, height: 900 } },
userMetadata: { workload: "migration-smoke" },
}),
});
if (!response.ok) throw new Error(await response.text());
const session = await response.json();
const browser = await chromium.connectOverCDP(session.connectUrl);
const context = browser.contexts()[0];
const page = context.pages()[0];
await page.goto("https://example.com");
console.log(await page.title());
await browser.close();
await fetch(`${api}/v1/sessions/${session.id}`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-bb-api-key": process.env.WEBX_API_KEY!,
},
body: JSON.stringify({ status: "REQUEST_RELEASE" }),
});
Stagehand compatibility smoke test
The repository pins the currently qualified Stagehand client and exercises its real Browserbase-mode provisioning + CDP attachment flow:
cd conformance/stagehand
npm ci
WEBX_API_KEY=... WEBX_URL=https://webx.agentslab.host npm run smoke
The smoke test initializes Stagehand with disableAPI: true, discovers its
active WebX page, navigates to Example Domain, validates the title/URL, and
closes the session. This catches compatibility drift in the public Stagehand
package instead of treating a generated snippet as proof.
The connectUrl contains a short-lived HMAC capability. It can access only
that session's /connect and /live data plane; it cannot call REST APIs or
reach another tenant's session.
Honest incompatibilities
WebX rejects options it cannot enforce rather than silently pretending they worked:
- Region routing is implemented, but a deployment advertises only the real
data planes configured through
WEBX_REGIONS; a single cluster therefore still serves one region. - Managed proxy leasing, geography, stickiness, metering, and receipts are
implemented, but operators must supply real upstream inventory through
WEBX_PROXY_POOL/WEBX_PROXY_POOL_FILE. External HTTP/SOCKS proxies are also accepted directly. - CAPTCHA detection, human takeover, solver invocation, token injection, and
clearance verification are implemented; automated solving requires an
operator-supplied
WEBX_CAPTCHA_SOLVER_URL. - Extension upload/execution and the Selenium gateway are implemented. WebX exposes a dedicated authenticated RemoteWebDriver endpoint rather than a legacy Selenium Grid hub, and session-create extension/proxy settings are preserved when ChromeDriver takes ownership.
Those are platform gaps, not response-shape gaps. They remain explicit so a migration cannot produce false confidence.