Connect with CDP

View as Markdown

A browser runtime is controlled through a connection: a short-lived lease that points your automation framework at the live browser.

Use connections for external tools such as Playwright, Puppeteer, Chrome debuggers, or other CDP-compatible clients. Use invocations when BCTRL should run hosted AI work inside the runtime.

Flow

  1. Create a space.
  2. Launch a browser runtime.
  3. Create a CDP connection.
  4. Pass the WebSocket URL to your browser framework.
  5. Inspect the current run through events, commands, artifacts, live view, and recording.

Launch a runtime

1const space = await bctrl.spaces.create({
2 name: "sales-workflow",
3});
4
5const runtime = await space.runtimes.browser.launch({
6 name: "crm",
7 profile: "sales-bot",
8});

Create a CDP connection

1const connection = await runtime.connections.create({
2 protocol: "cdp",
3 ttlSeconds: 600,
4});
5
6const wsUrl = connection.endpoint.url;

The endpoint URL is returned only by the create call. Connection list responses contain metadata, not signed attach URLs.

Drive it with Playwright

1import { chromium } from "playwright";
2
3const browser = await chromium.connectOverCDP(wsUrl);
4const context = browser.contexts()[0] ?? await browser.newContext();
5const page = context.pages()[0] ?? await context.newPage();
6
7await page.goto("https://example.com");
8console.log(await page.title());

Drive it with Puppeteer

1import puppeteer from "puppeteer";
2
3const browser = await puppeteer.connect({
4 browserWSEndpoint: wsUrl,
5});
6
7const page = await browser.newPage();
8await page.goto("https://example.com");

Revoke a connection

Connections expire automatically. Delete one early when you hand off control or finish the attach window.

1await runtime.connections.delete(connection.id);

Already-open connections finish according to the underlying lease. New attaches are refused.

Stop the runtime

1await runtime.stop();

Stopping a runtime tears down the browser and prevents new connection attaches.