@browserbasehq/tuna
v0.1.0
Published
JavaScript SDK for Stagehand driver.
Keywords
Readme
Stagehand SDK Client (JavaScript)
TypeScript SDK for controlling the Stagehand extension through ModCDP.
Run
From the repository root:
pnpm install
pnpm --filter @browserbasehq/tuna example:basicOr from this directory:
pnpm example:basicFor the CI smoke flow that exercises raw CDP, ModCDP, and GitHub summary output:
node --experimental-strip-types tests/e2e/basic_flow.tsUsage
import { Browser, Locator, Page, StagehandClient } from "@browserbasehq/tuna";
const client = new StagehandClient({
// Pass at most one launch source:
// cdp_url: "http://127.0.0.1:9222",
// cdp_url: "ws://127.0.0.1:9222/devtools/browser/<id>",
// local_browser_launch_options: {
// executable_path: "/Applications/Chromium.app/Contents/MacOS/Chromium",
// },
// browserbase_session_create_params: {
// browserbase_api_key: process.env.BROWSERBASE_API_KEY,
// },
});
await client.connect();
client.on("Target.targetInfoChanged", console.log);
console.log(await client.Browser.getVersion());
console.log(await client.Target.getTargets());
console.log(await client.Mod.evaluate({ expression: "chrome.runtime.id" }));
const browser: Browser = client.browser;
const page: Page = await browser.newPage({ url: "https://example.com" });
const page2: Page = await page.goto({ url: "https://browserbase.com" });
console.log(page2.url);
console.log(await browser.pages({ url: page2.url }));
const body: Locator = await page.locate({ css: "body" });
console.log(await body.info());
await client.close();Launch Sources
connect() accepts exactly one effective launch source:
cdp_url: an existing browser CDP endpoint.http://...URLs are resolved through/json/version;ws://...andwss://...URLs are used directly.local_browser_launch_options: launches local Chromium or Chrome Canary with CDP enabled.CHROME_PATHcan provide the executable path.STAGEHAND_SDK_CDP_PORTfixes the debugging port for editor attach workflows.browserbase_session_create_params.browserbase_api_key: asks ModCDP to create a Browserbase session.BROWSERBASE_EXTENSION_IDreuses an uploaded extension; otherwise the SDK rebuilds the extension output and ModCDP uploads/installs it.
If no launch source is passed, connect() reads .env/process.env; it uses BROWSERBASE_API_KEY when present, otherwise it launches local Chromium/Canary.
Extension Paths
The default extension directory is:
src/extension/.output/chrome-mv3If that output does not exist, the SDK falls back to:
dist/extension/chrome-mv3When the default .output/chrome-mv3 path is used and rebuild_extension !== false, the SDK runs the extension package build before connecting. The prepared extension manifest points at the deterministic ModCDP bootstrap service worker:
stagehand-modcdp/background.jsThe original WXT service worker is moved to:
stagehand-main/background.jsThe client trusts and waits for stagehand-modcdp/background.js with globalThis.__stagehand_modcdp_ready === true.
Routing
Default client routes:
{
"Mod.*": "service_worker",
"Custom.*": "service_worker",
"Stagehand.*": "service_worker",
"*.*": "service_worker",
}Default extension service-worker routes:
{
"Mod.*": "service_worker",
"Custom.*": "service_worker",
"Stagehand.*": "service_worker",
"*.*": "loopback_cdp",
}Stagehand SDK routes are fixed: Stagehand and ModCDP commands go through the extension service worker, and native CDP commands go from the service worker to loopback CDP.
Debugging
The checked-in VS Code tasks set:
STAGEHAND_DEBUG_WAIT_FOR_ENTER=1
STAGEHAND_SDK_CDP_PORT=9230The smoke test at tests/e2e/basic_flow.ts prints [debug] Browser ready. Press Enter to continue. after the extension is connected, so DevTools can inspect chrome-extension://*/background.js before the flow continues.
