Stagehand
Stagehand's act() and extract() drive a Boxline session's browser. Stagehand calls the model itself, with your own OpenAI key.
How it works
Stagehand v3: new Stagehand({ env: "LOCAL", localBrowserLaunchOptions: { cdpUrl: session.connectUrl }, model: { modelName, apiKey } }), then init(), act(), extract() with a zod schema. Create the session with keepAlive: true and release it after stagehand.close().
| Needs | any plan; your own OpenAI key. |
|---|---|
| Site | books.toscrape.com or quotes.toscrape.com, demo sites made for scraping practice. |
| Environment | BOXLINE_API_KEY, OPENAI_API_KEY (your OpenAI key: Stagehand calls OpenAI itself), STAGEHAND_MODEL (the model, as provider/model; default openai/gpt-6-luna). |
| Packages | @boxline/sdk, @browserbasehq/stagehand@3.7.3, tsx@4.23.15, zod@3.25.76 |
The code
/** * Stagehand with Boxline: Stagehand's act() and extract() drive a Boxline session's browser, connected by its CDP * address (Stagehand v3: env "LOCAL" with localBrowserLaunchOptions.cdpUrl). Stagehand calls the model itself, with * your own OpenAI key. * * npm install && npx tsx index.ts (BOXLINE_API_KEY and OPENAI_API_KEY in the environment; STAGEHAND_MODEL) * * Stagehand v4 connects differently: it loads its own browser extension from this computer's disk and needs the * `debugger` permission, which Boxline sessions do not accept. Use v3 with Boxline. Writes output/result.json. */import { mkdirSync, writeFileSync } from "node:fs";import { join } from "node:path";import { Boxline } from "@boxline/sdk";import { Stagehand } from "@browserbasehq/stagehand";import { z } from "zod";const out = process.env.OUTPUT_DIR ?? "output";const modelName = process.env.STAGEHAND_MODEL ?? "openai/gpt-6-luna";if (!process.env.OPENAI_API_KEY) throw new Error("Set OPENAI_API_KEY: Stagehand calls the model itself");const bx = new Boxline();// keepAlive: the session stays up while Stagehand connects, and until it is stopped below.const session = await bx.sessions.create({ timeout: 600, keepAlive: true, userMetadata: { example: "integrations/stagehand" } });console.log(`Session: ${session.id}`);const stagehand = new Stagehand({ env: "LOCAL", localBrowserLaunchOptions: { cdpUrl: session.connectUrl! }, // a signed address: treat it like a password model: { modelName, apiKey: process.env.OPENAI_API_KEY }, verbose: 0, disablePino: true,});try { await stagehand.init(); const page = stagehand.context.pages()[0]!; await page.goto("https://books.toscrape.com/"); const act = await stagehand.act("click the Poetry category in the list of book categories"); console.log(`act: ${act.message}`); const { books } = await stagehand.extract( "the title and price of the first 5 books listed on this page", z.object({ books: z.array(z.object({ title: z.string(), price: z.string().describe("as shown, e.g. £51.77") })) }), ); const url = page.url(); const metrics = await stagehand.metrics; console.log(`${url}: ${books.length} books, e.g. ${books[0]?.title} ${books[0]?.price}`); mkdirSync(out, { recursive: true }); writeFileSync( join(out, "result.json"), JSON.stringify( { sessionId: session.id, model: modelName, act: { success: act.success, message: act.message }, url, books, usage: { ownModelTokens: metrics.totalPromptTokens + metrics.totalCompletionTokens } }, null, 2, ), );} finally { await stagehand.close().catch(() => undefined); await session.stop();}Install and run
The packages are pinned at the versions the example’s check ran with. It writes to output/ and stops its session when it finishes.
# Node 22 or newerexport BOXLINE_API_KEY=… # your Boxline API keyexport OPENAI_API_KEY=… # your own OpenAI keynpm install @boxline/sdk @browserbasehq/stagehand@3.7.3 tsx@4.23.15 zod@3.25.76npx tsx index.tsWhat its check proves
It checks that act() opened the Poetry category and extract() read its first 5 books with the prices the site shows. To run it from a clone of the examples (git clone https://github.com/Boxline-dev/examples.git), go to examples/integrations/stagehand, run the commands above, then check the result from the same folder: npx tsx check.ts output.
Source: github.com/Boxline-dev/examples/integrations/stagehand on GitHub. See all integrations.
These docs describe a beta API. Endpoints, fields and SDK methods may change before general availability; breaking changes will be listed in the changelog.