# 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

```ts
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:

```bash
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.
