ax-check.com
by Gauge
B
Browserbase
browserbase.com
ax-check.com
Checked 15 October 2026
A
100/100
Agents need your login
Browserbase gets agents running and pricing-sure, every time.
All 23 checklist items passed: docs, quickstarts, API/MCP/CLI, and pricing are all openly readable with no login wall. All 3 agent sessions completed and nailed pricing.
1 fix to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no browserbase.com account. Recorded 15 October 2026 on Pi.
3 recorded · 2m 57s
2m 57s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
Let me look at the current state of the repository.
pwd && ls -la
/sandbox/repo
/sandbox/repo total 16 drwxr-xr-x 3 root root 4096 Sep 18 08:00 . drwxr-xr-x 7 root root 4096 Oct 15 09:33 .. drwxr-xr-x 8 root root 4096 Sep 24 20:05 .git -rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore
Recorded tool call
{
"type": "tool_call",
"seq": 3,
"ts": "2026-10-15T09:33:20.870Z",
"name": "bash",
"turn": 1,
"input": {
"command": "pwd && ls -la"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-bf6b2b08e543e42f",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 4,
"ts": "2026-10-15T09:33:20.870Z",
"turn": 1,
"output": {
"content": [
{
"text": "/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Oct 15 09:33 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05 .git\n-rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-bf6b2b08e543e42f",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Empty repo. Let me check network access, and whether there's a BROWSERBASE_API_KEY in env.
Let me check if npm install works and if we can reach Browserbase API.
cd /sandbox/repo && cat .gitignore; env | grep -i -E "browserbase|proxy|http" ; echo "---"; node -v; npm -v; python3 -V
# Keep generated and vendored files out of source diffs.
# Keep generated and vendored files out of source diffs. # Logs / OS cruft *.log .DS_Store # JavaScript / TypeScript node_modules/ .next/ dist/ build/ coverage/ # Python .venv/ venv/ __pycache__/ *.py[cod] .pytest_cache/ *.egg-info/ # Rust target/ # Go / PHP / Ruby vendored deps vendor/ .bundle/ # Java / Kotlin / Scala .gradle/ # .NET bin/ obj/ # Elixir _build/ deps/ # Dart / Flutter .dart_tool/ CARGO_HTTP_CAINFO=/etc/ssl/certs/ca-certificates.crt --- v22.23.2 10.9.8 Python 3.12.3
Recorded tool call
{
"type": "tool_call",
"seq": 7,
"ts": "2026-10-15T09:33:26.055Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && cat .gitignore; env | grep -i -E \"browserbase|proxy|http\" ; echo \"---\"; node -v; npm -v; python3 -V"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-89802778c93de8bf",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 8,
"ts": "2026-10-15T09:33:26.378Z",
"turn": 1,
"output": {
"content": [
{
"text": "# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/\n.next/\ndist/\nbuild/\ncoverage/\n\n# Python\n.venv/\nvenv/\n__pycache__/\n*.py[cod]\n.pytest_cache/\n*.egg-info/\n\n# Rust\ntarget/\n\n# Go / PHP / Ruby vendored deps\nvendor/\n.bundle/\n\n# Java / Kotlin / Scala\n.gradle/\n\n# .NET\nbin/\nobj/\n\n# Elixir\n_build/\ndeps/\n\n# Dart / Flutter\n.dart_tool/\nCARGO_HTTP_CAINFO=/etc/ssl/certs/ca-certificates.crt\n---\nv22.23.2\n10.9.8\nPython 3.12.3\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-89802778c93de8bf",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
No BROWSERBASE_API_KEY. Let's check network connectivity to npm registry and browserbase API.
cd /tmp && timeout 30 curl -s -o /dev/null -w "npm:%{http_code}\n" https://registry.npmjs.org/@browserbasehq/sdk ; timeout 30 curl -s -o /dev/null -w "bb-api:%{http_code}\n" https://api.browserbase.com/v1/projects ; timeout 30 curl -s -o /dev/null -w "docs:%{http_code}\n" https://docs.browserbase.com/npm:200
npm:200 bb-api:401 docs:308
Recorded tool call
{
"type": "tool_call",
"seq": 11,
"ts": "2026-10-15T09:33:31.088Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 30 curl -s -o /dev/null -w \"npm:%{http_code}\\n\" https://registry.npmjs.org/@browserbasehq/sdk ; timeout 30 curl -s -o /dev/null -w \"bb-api:%{http_code}\\n\" https://api.browserbase.com/v1/projects ; timeout 30 curl -s -o /dev/null -w \"docs:%{http_code}\\n\" https://docs.browserbase.com/"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-b77502007641457f",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 12,
"ts": "2026-10-15T09:33:33.100Z",
"turn": 1,
"output": {
"content": [
{
"text": "npm:200\nbb-api:401\ndocs:308\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-b77502007641457f",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Network works, npm registry reachable. API returns 401 without key (expected). No API key in env, so I can't actually run it live. I should build the example, and report that I can't run it end-to-end without credentials.
Let me get the latest SDK version and check the SDK surface so I write accurate code.
cd /tmp && timeout 60 npm view @browserbasehq/sdk version dist-tags description repository.url 2>&1 | head -30; echo "=== stagehand ==="; timeout 60 npm view @browserbasehq/stagehand version description 2>&1 | head -10
version = '2.22.0'
version = '2.22.0'
dist-tags = { next: '1.4.3-next.0', alpha: '2.8.0-alpha.1', latest: '2.22.0' }
description = 'The official Node.js library for the Browserbase API'
repository.url = 'git+https://github.com/browserbase/sdk-node.git'
=== stagehand ===
version = '4.2.1'
description = "Browserbase's SDK for building browser agents"
Recorded tool call
{
"type": "tool_call",
"seq": 15,
"ts": "2026-10-15T09:33:36.926Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 60 npm view @browserbasehq/sdk version dist-tags description repository.url 2>&1 | head -30; echo \"=== stagehand ===\"; timeout 60 npm view @browserbasehq/stagehand version description 2>&1 | head -10"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-996a86b0d1ea121e",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 16,
"ts": "2026-10-15T09:33:39.862Z",
"turn": 1,
"output": {
"content": [
{
"text": "version = '2.22.0'\ndist-tags = { next: '1.4.3-next.0', alpha: '2.8.0-alpha.1', latest: '2.22.0' }\ndescription = 'The official Node.js library for the Browserbase API'\nrepository.url = 'git+https://github.com/browserbase/sdk-node.git'\n=== stagehand ===\nversion = '4.2.1'\ndescription = \"Browserbase's SDK for building browser agents\"\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-996a86b0d1ea121e",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Let me install the SDK into the repo so I can inspect the actual API surface (types) to write accurate code. That's a light dependency install, not a service stack. Let's do it.
cd /sandbox/repo && timeout 300 npm init -y >/dev/null 2>&1 && timeout 300 npm i @browserbasehq/sdk@2.22.0 2>&1 | tail -5
6 packages are looking for funding
6 packages are looking for funding run `npm fund` for details found 0 vulnerabilities
Recorded tool call
{
"type": "tool_call",
"seq": 19,
"ts": "2026-10-15T09:33:44.539Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && timeout 300 npm init -y >/dev/null 2>&1 && timeout 300 npm i @browserbasehq/sdk@2.22.0 2>&1 | tail -5"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-ad2cc6fb456d6bc8",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 20,
"ts": "2026-10-15T09:33:53.671Z",
"turn": 1,
"output": {
"content": [
{
"text": "\n6 packages are looking for funding\n run `npm fund` for details\n\nfound 0 vulnerabilities\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-ad2cc6fb456d6bc8",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Now let me inspect the SDK surface to write accurate code. Check Browserbase class, sessions.create options, debug fileURL, etc.
cd /sandbox/repo && ls node_modules/@browserbasehq/sdk/ && ls node_modules/@browserbasehq/sdk/resources/ && cat node_modules/@browserbasehq/sdk/package.json | head -40
CHANGELOG.md
CHANGELOG.md
LICENSE
README.md
_shims
core.d.ts
core.d.ts.map
core.js
core.js.map
core.mjs
core.mjs.map
error.d.ts
error.d.ts.map
error.js
error.js.map
error.mjs
error.mjs.map
index.d.mts
index.d.ts
index.d.ts.map
index.js
index.js.map
index.mjs
index.mjs.map
internal
package.json
resource.d.ts
resource.d.ts.map
resource.js
resource.js.map
resource.mjs
resource.mjs.map
resources
resources.d.ts
resources.d.ts.map
resources.js
resources.js.map
resources.mjs
resources.mjs.map
shims
src
uploads.d.ts
uploads.d.ts.map
uploads.js
uploads.js.map
uploads.mjs
uploads.mjs.map
version.d.ts
version.d.ts.map
version.js
version.js.map
version.mjs
version.mjs.map
agents
agents.d.ts
agents.d.ts.map
agents.js
agents.js.map
agents.mjs
agents.mjs.map
certificates.d.ts
certificates.d.ts.map
certificates.js
certificates.js.map
certificates.mjs
certificates.mjs.map
contexts.d.ts
contexts.d.ts.map
contexts.js
contexts.js.map
contexts.mjs
contexts.mjs.map
extensions.d.ts
extensions.d.ts.map
extensions.js
extensions.js.map
extensions.mjs
extensions.mjs.map
fetch-api.d.ts
fetch-api.d.ts.map
fetch-api.js
fetch-api.js.map
fetch-api.mjs
fetch-api.mjs.map
functions
functions.d.ts
functions.d.ts.map
functions.js
functions.js.map
functions.mjs
functions.mjs.map
index.d.ts
index.d.ts.map
index.js
index.js.map
index.mjs
index.mjs.map
projects.d.ts
projects.d.ts.map
projects.js
projects.js.map
projects.mjs
projects.mjs.map
search.d.ts
search.d.ts.map
search.js
search.js.map
search.mjs
search.mjs.map
secrets.d.ts
secrets.d.ts.map
secrets.js
secrets.js.map
secrets.mjs
secrets.mjs.map
sessions
sessions.d.ts
sessions.d.ts.map
sessions.js
sessions.js.map
sessions.mjs
sessions.mjs.map
webhooks.d.ts
webhooks.d.ts.map
webhooks.js
webhooks.js.map
webhooks.mjs
webhooks.mjs.map
{
"name": "@browserbasehq/sdk",
"version": "2.22.0",
"description": "The official Node.js library for the Browserbase API",
"author": "Browserbase <support@browserbase.com>",
"license": "Apache-2.0",
"types": "./index.d.ts",
"main": "./index.js",
"type": "commonjs",
"repository": "github:browserbase/sdk-node",
"packageManager": "yarn@1.22.22",
"files": [
"**/*"
],
"private": false,
"publishConfig": {
"access": "public"
},
"scripts": {
"test": "./scripts/test",
"build": "./scripts/build",
"format": "prettier --write --cache --cache-strategy metadata . !dist",
"tsn": "ts-node -r tsconfig-paths/register",
"lint": "./scripts/lint",
"fix": "./scripts/format"
},
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1",
"form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2",
"node-fetch": "^2.6.7"
},
"sideEffects": [
"./_shims/index.js",
"./_shims/index.mjs",
"./shims/node.js",
"./shims/node.mjs",
Recorded tool call
{
"type": "tool_call",
"seq": 23,
"ts": "2026-10-15T09:33:58.116Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && ls node_modules/@browserbasehq/sdk/ && ls node_modules/@browserbasehq/sdk/resources/ && cat node_modules/@browserbasehq/sdk/package.json | head -40"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-b8b38f2577fff4b6",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 24,
"ts": "2026-10-15T09:33:58.116Z",
"turn": 1,
"output": {
"content": [
{
"text": "CHANGELOG.md\nLICENSE\nREADME.md\n_shims\ncore.d.ts\ncore.d.ts.map\ncore.js\ncore.js.map\ncore.mjs\ncore.mjs.map\nerror.d.ts\nerror.d.ts.map\nerror.js\nerror.js.map\nerror.mjs\nerror.mjs.map\nindex.d.mts\nindex.d.ts\nindex.d.ts.map\nindex.js\nindex.js.map\nindex.mjs\nindex.mjs.map\ninternal\npackage.json\nresource.d.ts\nresource.d.ts.map\nresource.js\nresource.js.map\nresource.mjs\nresource.mjs.map\nresources\nresources.d.ts\nresources.d.ts.map\nresources.js\nresources.js.map\nresources.mjs\nresources.mjs.map\nshims\nsrc\nuploads.d.ts\nuploads.d.ts.map\nuploads.js\nuploads.js.map\nuploads.mjs\nuploads.mjs.map\nversion.d.ts\nversion.d.ts.map\nversion.js\nversion.js.map\nversion.mjs\nversion.mjs.map\nagents\nagents.d.ts\nagents.d.ts.map\nagents.js\nagents.js.map\nagents.mjs\nagents.mjs.map\ncertificates.d.ts\ncertificates.d.ts.map\ncertificates.js\ncertificates.js.map\ncertificates.mjs\ncertificates.mjs.map\ncontexts.d.ts\ncontexts.d.ts.map\ncontexts.js\ncontexts.js.map\ncontexts.mjs\ncontexts.mjs.map\nextensions.d.ts\nextensions.d.ts.map\nextensions.js\nextensions.js.map\nextensions.mjs\nextensions.mjs.map\nfetch-api.d.ts\nfetch-api.d.ts.map\nfetch-api.js\nfetch-api.js.map\nfetch-api.mjs\nfetch-api.mjs.map\nfunctions\nfunctions.d.ts\nfunctions.d.ts.map\nfunctions.js\nfunctions.js.map\nfunctions.mjs\nfunctions.mjs.map\nindex.d.ts\nindex.d.ts.map\nindex.js\nindex.js.map\nindex.mjs\nindex.mjs.map\nprojects.d.ts\nprojects.d.ts.map\nprojects.js\nprojects.js.map\nprojects.mjs\nprojects.mjs.map\nsearch.d.ts\nsearch.d.ts.map\nsearch.js\nsearch.js.map\nsearch.mjs\nsearch.mjs.map\nsecrets.d.ts\nsecrets.d.ts.map\nsecrets.js\nsecrets.js.map\nsecrets.mjs\nsecrets.mjs.map\nsessions\nsessions.d.ts\nsessions.d.ts.map\nsessions.js\nsessions.js.map\nsessions.mjs\nsessions.mjs.map\nwebhooks.d.ts\nwebhooks.d.ts.map\nwebhooks.js\nwebhooks.js.map\nwebhooks.mjs\nwebhooks.mjs.map\n{\n \"name\": \"@browserbasehq/sdk\",\n \"version\": \"2.22.0\",\n \"description\": \"The official Node.js library for the Browserbase API\",\n \"author\": \"Browserbase <support@browserbase.com>\",\n \"license\": \"Apache-2.0\",\n \"types\": \"./index.d.ts\",\n \"main\": \"./index.js\",\n \"type\": \"commonjs\",\n \"repository\": \"github:browserbase/sdk-node\",\n \"packageManager\": \"yarn@1.22.22\",\n \"files\": [\n \"**/*\"\n ],\n \"private\": false,\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"test\": \"./scripts/test\",\n \"build\": \"./scripts/build\",\n \"format\": \"prettier --write --cache --cache-strategy metadata . !dist\",\n \"tsn\": \"ts-node -r tsconfig-paths/register\",\n \"lint\": \"./scripts/lint\",\n \"fix\": \"./scripts/format\"\n },\n \"dependencies\": {\n \"@types/node\": \"^18.11.18\",\n \"@types/node-fetch\": \"^2.6.4\",\n \"abort-controller\": \"^3.0.0\",\n \"agentkeepalive\": \"^4.2.1\",\n \"form-data-encoder\": \"1.7.2\",\n \"formdata-node\": \"^4.3.2\",\n \"node-fetch\": \"^2.6.7\"\n },\n \"sideEffects\": [\n \"./_shims/index.js\",\n \"./_shims/index.mjs\",\n \"./shims/node.js\",\n \"./shims/node.mjs\",\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-b8b38f2577fff4b6",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Now let's inspect the key APIs: sessions.create params, session.debug fileURL, connectUrl, browser.url. Let me look at sessions.d.ts and sessions/sessions.d.ts.
cd /sandbox/repo/node_modules/@browserbasehq/sdk && grep -n "connectUrl\|debugUrl\|interface SessionCreateResponse\|export interface CreateParams" resources/sessions/sessions.d.ts | head -40; echo "=== create params ==="; sed -n '/export interface CreateParams/,/^}/p' resources/sessions/sessions.d.ts | head -120
95:export interface SessionCreateResponse extends Session {
95:export interface SessionCreateResponse extends Session {
99: connectUrl: string;
113: connectUrl?: string;
=== create params ===
Recorded tool call
{
"type": "tool_call",
"seq": 27,
"ts": "2026-10-15T09:34:00.633Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/node_modules/@browserbasehq/sdk && grep -n \"connectUrl\\|debugUrl\\|interface SessionCreateResponse\\|export interface CreateParams\" resources/sessions/sessions.d.ts | head -40; echo \"=== create params ===\"; sed -n '/export interface CreateParams/,/^}/p' resources/sessions/sessions.d.ts | head -120"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-9059d5b884d2b95b",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 28,
"ts": "2026-10-15T09:34:00.633Z",
"turn": 1,
"output": {
"content": [
{
"text": "95:export interface SessionCreateResponse extends Session {\n99: connectUrl: string;\n113: connectUrl?: string;\n=== create params ===\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-9059d5b884d2b95b",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Let me look at sessions.d.ts create params properly.
cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '1,140p' resources/sessions/sessions.d.ts
import { APIResource } from "../../resource.js";
import { APIResource } from "../../resource.js";
import * as Core from "../../core.js";
import * as DownloadsAPI from "./downloads.js";
import { Downloads } from "./downloads.js";
import * as LogsAPI from "./logs.js";
import { LogListResponse, Logs, SessionLog } from "./logs.js";
import * as ReplaysAPI from "./replays.js";
import { ReplayRetrieveResponse, Replays } from "./replays.js";
import * as UploadsAPI from "./uploads.js";
import { UploadCreateParams, UploadCreateResponse, Uploads } from "./uploads.js";
import * as RecordingAPI from "./recording/recording.js";
import { Recording, RecordingRetrieveResponse, SessionRecording } from "./recording/recording.js";
export declare class Sessions extends APIResource {
downloads: DownloadsAPI.Downloads;
logs: LogsAPI.Logs;
recording: RecordingAPI.Recording;
uploads: UploadsAPI.Uploads;
replays: ReplaysAPI.Replays;
/**
* Create a Session
*/
create(params?: SessionCreateParams, options?: Core.RequestOptions): Core.APIPromise<SessionCreateResponse>;
create(options?: Core.RequestOptions): Core.APIPromise<SessionCreateResponse>;
/**
* Get a Session
*/
retrieve(id: string, options?: Core.RequestOptions): Core.APIPromise<SessionRetrieveResponse>;
/**
* Update a Session
*/
update(id: string, body: SessionUpdateParams, options?: Core.RequestOptions): Core.APIPromise<Session>;
/**
* List Sessions
*/
list(query?: SessionListParams, options?: Core.RequestOptions): Core.APIPromise<SessionListResponse>;
list(options?: Core.RequestOptions): Core.APIPromise<SessionListResponse>;
/**
* Session Live URLs
*/
debug(id: string, query?: SessionDebugParams, options?: Core.RequestOptions): Core.APIPromise<SessionLiveURLs>;
debug(id: string, options?: Core.RequestOptions): Core.APIPromise<SessionLiveURLs>;
}
export interface Session {
id: string;
createdAt: string;
expiresAt: string;
/**
* Indicates if the Session was created to be kept alive upon disconnections
*/
keepAlive: boolean;
/**
* The Project ID linked to the Session.
*/
projectId: string;
/**
* Bytes used via the [Proxy](/features/stealth-mode#proxies-and-residential-ips)
*/
proxyBytes: number;
/**
* The region where the Session is running.
*/
region: 'us-west-2' | 'us-east-1' | 'eu-central-1' | 'ap-southeast-1';
startedAt: string;
status: 'PENDING' | 'RUNNING' | 'ERROR' | 'TIMED_OUT' | 'COMPLETED';
updatedAt: string;
/**
* Optional. The Context linked to the Session.
*/
contextId?: string;
endedAt?: string;
/**
* Arbitrary user metadata to attach to the session. To learn more about user
* metadata, see [User Metadata](/features/sessions#user-metadata).
*/
userMetadata?: {
[key: string]: unknown;
};
}
export interface SessionLiveURLs {
debuggerFullscreenUrl: string;
debuggerUrl: string;
pages: Array<SessionLiveURLs.Page>;
wsUrl: string;
}
export declare namespace SessionLiveURLs {
interface Page {
id: string;
debuggerFullscreenUrl: string;
debuggerUrl: string;
faviconUrl: string;
title: string;
url: string;
}
}
export interface SessionCreateResponse extends Session {
/**
* WebSocket URL to connect to the Session.
*/
connectUrl: string;
/**
* HTTP URL to connect to the Session.
*/
seleniumRemoteUrl: string;
/**
* Signing key to use when connecting to the Session via HTTP.
*/
signingKey: string;
}
export interface SessionRetrieveResponse extends Session {
/**
* WebSocket URL to connect to the Session.
*/
connectUrl?: string;
/**
* HTTP URL to connect to the Session.
*/
seleniumRemoteUrl?: string;
/**
* Signing key to use when connecting to the Session via HTTP.
*/
signingKey?: string;
}
export type SessionListResponse = Array<Session>;
export interface SessionCreateParams {
browserSettings?: SessionCreateParams.BrowserSettings;
/**
* The uploaded Extension ID. See
* [Upload Extension](/reference/api/upload-an-extension).
*/
extensionId?: string;
/**
* Set to true to keep the session alive even after disconnections. Available on
* the Hobby Plan and above.
*/
keepAlive?: boolean;
/**
* The Project ID. Can be found in
* [Settings](https://www.browserbase.com/settings). Optional - if not provided,
* the project will be inferred from the API key.
*/
Recorded tool call
{
"type": "tool_call",
"seq": 31,
"ts": "2026-10-15T09:34:02.743Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '1,140p' resources/sessions/sessions.d.ts"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a062260b3f60bba7",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 32,
"ts": "2026-10-15T09:34:02.743Z",
"turn": 1,
"output": {
"content": [
{
"text": "import { APIResource } from \"../../resource.js\";\nimport * as Core from \"../../core.js\";\nimport * as DownloadsAPI from \"./downloads.js\";\nimport { Downloads } from \"./downloads.js\";\nimport * as LogsAPI from \"./logs.js\";\nimport { LogListResponse, Logs, SessionLog } from \"./logs.js\";\nimport * as ReplaysAPI from \"./replays.js\";\nimport { ReplayRetrieveResponse, Replays } from \"./replays.js\";\nimport * as UploadsAPI from \"./uploads.js\";\nimport { UploadCreateParams, UploadCreateResponse, Uploads } from \"./uploads.js\";\nimport * as RecordingAPI from \"./recording/recording.js\";\nimport { Recording, RecordingRetrieveResponse, SessionRecording } from \"./recording/recording.js\";\nexport declare class Sessions extends APIResource {\n downloads: DownloadsAPI.Downloads;\n logs: LogsAPI.Logs;\n recording: RecordingAPI.Recording;\n uploads: UploadsAPI.Uploads;\n replays: ReplaysAPI.Replays;\n /**\n * Create a Session\n */\n create(params?: SessionCreateParams, options?: Core.RequestOptions): Core.APIPromise<SessionCreateResponse>;\n create(options?: Core.RequestOptions): Core.APIPromise<SessionCreateResponse>;\n /**\n * Get a Session\n */\n retrieve(id: string, options?: Core.RequestOptions): Core.APIPromise<SessionRetrieveResponse>;\n /**\n * Update a Session\n */\n update(id: string, body: SessionUpdateParams, options?: Core.RequestOptions): Core.APIPromise<Session>;\n /**\n * List Sessions\n */\n list(query?: SessionListParams, options?: Core.RequestOptions): Core.APIPromise<SessionListResponse>;\n list(options?: Core.RequestOptions): Core.APIPromise<SessionListResponse>;\n /**\n * Session Live URLs\n */\n debug(id: string, query?: SessionDebugParams, options?: Core.RequestOptions): Core.APIPromise<SessionLiveURLs>;\n debug(id: string, options?: Core.RequestOptions): Core.APIPromise<SessionLiveURLs>;\n}\nexport interface Session {\n id: string;\n createdAt: string;\n expiresAt: string;\n /**\n * Indicates if the Session was created to be kept alive upon disconnections\n */\n keepAlive: boolean;\n /**\n * The Project ID linked to the Session.\n */\n projectId: string;\n /**\n * Bytes used via the [Proxy](/features/stealth-mode#proxies-and-residential-ips)\n */\n proxyBytes: number;\n /**\n * The region where the Session is running.\n */\n region: 'us-west-2' | 'us-east-1' | 'eu-central-1' | 'ap-southeast-1';\n startedAt: string;\n status: 'PENDING' | 'RUNNING' | 'ERROR' | 'TIMED_OUT' | 'COMPLETED';\n updatedAt: string;\n /**\n * Optional. The Context linked to the Session.\n */\n contextId?: string;\n endedAt?: string;\n /**\n * Arbitrary user metadata to attach to the session. To learn more about user\n * metadata, see [User Metadata](/features/sessions#user-metadata).\n */\n userMetadata?: {\n [key: string]: unknown;\n };\n}\nexport interface SessionLiveURLs {\n debuggerFullscreenUrl: string;\n debuggerUrl: string;\n pages: Array<SessionLiveURLs.Page>;\n wsUrl: string;\n}\nexport declare namespace SessionLiveURLs {\n interface Page {\n id: string;\n debuggerFullscreenUrl: string;\n debuggerUrl: string;\n faviconUrl: string;\n title: string;\n url: string;\n }\n}\nexport interface SessionCreateResponse extends Session {\n /**\n * WebSocket URL to connect to the Session.\n */\n connectUrl: string;\n /**\n * HTTP URL to connect to the Session.\n */\n seleniumRemoteUrl: string;\n /**\n * Signing key to use when connecting to the Session via HTTP.\n */\n signingKey: string;\n}\nexport interface SessionRetrieveResponse extends Session {\n /**\n * WebSocket URL to connect to the Session.\n */\n connectUrl?: string;\n /**\n * HTTP URL to connect to the Session.\n */\n seleniumRemoteUrl?: string;\n /**\n * Signing key to use when connecting to the Session via HTTP.\n */\n signingKey?: string;\n}\nexport type SessionListResponse = Array<Session>;\nexport interface SessionCreateParams {\n browserSettings?: SessionCreateParams.BrowserSettings;\n /**\n * The uploaded Extension ID. See\n * [Upload Extension](/reference/api/upload-an-extension).\n */\n extensionId?: string;\n /**\n * Set to true to keep the session alive even after disconnections. Available on\n * the Hobby Plan and above.\n */\n keepAlive?: boolean;\n /**\n * The Project ID. Can be found in\n * [Settings](https://www.browserbase.com/settings). Optional - if not provided,\n * the project will be inferred from the API key.\n */\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a062260b3f60bba7",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Good. Now let me check the rest of SessionCreateParams (browserSettings, proxies) and the constructor options for Browserbase.
Also I should decide the demo. The simplest "hello world" using only the SDK without puppeteer: create a session, but you need to drive the browser via CDP. Without puppeteer/playwright you can't do much. But puppeteer-core is light (a client library, no Chromium download). That's fine — it's not a local service stack; it connects to the hosted browser via connectUrl.
Actually, puppeteer-core install is light (~few MB, no browser binary). Let's check. Alternatively use Stagehand which needs an OpenAI key. Better: plain SDK + puppeteer-core to navigate and get title/HTML.
Let me check what SessionCreateParams.BrowserSettings supports and the proxy options.
cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '140,230p' resources/sessions/sessions.d.ts; echo "=== client opts ==="; grep -n "apiKey\|projectId\|constructor\|maxRetries\|timeout" index.d.ts | head -30
*/
*/
projectId?: string;
/**
* Proxy configuration. Can be true for default proxy, or an array of proxy
* configurations.
*/
proxies?: Array<SessionCreateParams.BrowserbaseProxyConfig | SessionCreateParams.ExternalProxyConfig | SessionCreateParams.NoneProxyConfig> | boolean;
/**
* Supplementary proxy settings. Optional.
*/
proxySettings?: SessionCreateParams.ProxySettings;
/**
* The region where the Session should run.
*/
region?: 'us-west-2' | 'us-east-1' | 'eu-central-1' | 'ap-southeast-1';
/**
* Duration in seconds after which the session will automatically end. Defaults to
* the Project's `defaultTimeout`. Minimum 60 seconds, maximum 21600 seconds (6
* hours).
*/
api_timeout?: number;
/**
* Arbitrary user metadata to attach to the session. To learn more about user
* metadata, see [User Metadata](/features/sessions#user-metadata).
*/
userMetadata?: {
[key: string]: unknown;
};
}
export declare namespace SessionCreateParams {
interface BrowserSettings {
/**
* @deprecated Advanced Browser Stealth Mode. Deprecated: use `verified` instead.
*/
advancedStealth?: boolean;
/**
* An optional list of allowed domains for the session. If you pass one or more
* domains, Browserbase restricts top-level (main-frame) page navigations to the
* listed domains and their subdomains. For example, `example.com` also permits
* `www.example.com` and `a.b.example.com`, but not `notexample.com`. Matching is
* domain-based, not full-URL. An empty list (the default) disables the restriction
* entirely. Browserbase enforces only main-frame navigations; it does not block
* iframe/subframe loads or other in-page resource requests (images, scripts, XHR,
* etc.).
*/
allowedDomains?: Array<string>;
/**
* Enable or disable ad blocking in the browser. Defaults to `false`.
*/
blockAds?: boolean;
/**
* Custom selector for captcha image. See
* [Custom Captcha Solving](/features/stealth-mode#custom-captcha-solving)
*/
captchaImageSelector?: string;
/**
* Custom selector for captcha input. See
* [Custom Captcha Solving](/features/stealth-mode#custom-captcha-solving)
*/
captchaInputSelector?: string;
context?: BrowserSettings.Context;
/**
* The uploaded Extension ID. See
* [Upload Extension](/reference/api/upload-an-extension).
*/
extensionId?: string;
/**
* Enable or disable ignoring of certificate errors in the browser. Defaults to
* `false`, so TLS certificate validation is enforced; set to `true` to ignore
* certificate errors (for example, to reach hosts with expired or self-signed
* certificates).
*/
ignoreCertificateErrors?: boolean;
/**
* Enable or disable session logging. Defaults to `true`.
*/
logSession?: boolean;
/**
* Operating system for stealth mode. Valid values: windows, mac, linux, mobile,
* tablet
*/
os?: 'windows' | 'mac' | 'linux' | 'mobile' | 'tablet';
/**
* Enable or disable session recording. Defaults to `true`.
*/
recordSession?: boolean;
/**
* Enable or disable captcha solving in the browser. Defaults to `true`.
*/
solveCaptchas?: boolean;
/**
=== client opts ===
21: apiKey?: string | undefined;
32: * Note that request timeouts are retried by default, so in a worst-case scenario you may wait
33: * much longer than this timeout before the promise succeeds or fails.
37: timeout?: number | undefined;
60: maxRetries?: number | undefined;
81: apiKey: string;
86: * @param {string | undefined} [opts.apiKey=process.env['BROWSERBASE_API_KEY'] ?? undefined]
88: * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
91: * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
95: constructor({ baseURL, apiKey, ...opts }?: ClientOptions);
Recorded tool call
{
"type": "tool_call",
"seq": 35,
"ts": "2026-10-15T09:34:07.620Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '140,230p' resources/sessions/sessions.d.ts; echo \"=== client opts ===\"; grep -n \"apiKey\\|projectId\\|constructor\\|maxRetries\\|timeout\" index.d.ts | head -30"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-adb8b8af71b2dcc9",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 36,
"ts": "2026-10-15T09:34:07.620Z",
"turn": 1,
"output": {
"content": [
{
"text": " */\n projectId?: string;\n /**\n * Proxy configuration. Can be true for default proxy, or an array of proxy\n * configurations.\n */\n proxies?: Array<SessionCreateParams.BrowserbaseProxyConfig | SessionCreateParams.ExternalProxyConfig | SessionCreateParams.NoneProxyConfig> | boolean;\n /**\n * Supplementary proxy settings. Optional.\n */\n proxySettings?: SessionCreateParams.ProxySettings;\n /**\n * The region where the Session should run.\n */\n region?: 'us-west-2' | 'us-east-1' | 'eu-central-1' | 'ap-southeast-1';\n /**\n * Duration in seconds after which the session will automatically end. Defaults to\n * the Project's `defaultTimeout`. Minimum 60 seconds, maximum 21600 seconds (6\n * hours).\n */\n api_timeout?: number;\n /**\n * Arbitrary user metadata to attach to the session. To learn more about user\n * metadata, see [User Metadata](/features/sessions#user-metadata).\n */\n userMetadata?: {\n [key: string]: unknown;\n };\n}\nexport declare namespace SessionCreateParams {\n interface BrowserSettings {\n /**\n * @deprecated Advanced Browser Stealth Mode. Deprecated: use `verified` instead.\n */\n advancedStealth?: boolean;\n /**\n * An optional list of allowed domains for the session. If you pass one or more\n * domains, Browserbase restricts top-level (main-frame) page navigations to the\n * listed domains and their subdomains. For example, `example.com` also permits\n * `www.example.com` and `a.b.example.com`, but not `notexample.com`. Matching is\n * domain-based, not full-URL. An empty list (the default) disables the restriction\n * entirely. Browserbase enforces only main-frame navigations; it does not block\n * iframe/subframe loads or other in-page resource requests (images, scripts, XHR,\n * etc.).\n */\n allowedDomains?: Array<string>;\n /**\n * Enable or disable ad blocking in the browser. Defaults to `false`.\n */\n blockAds?: boolean;\n /**\n * Custom selector for captcha image. See\n * [Custom Captcha Solving](/features/stealth-mode#custom-captcha-solving)\n */\n captchaImageSelector?: string;\n /**\n * Custom selector for captcha input. See\n * [Custom Captcha Solving](/features/stealth-mode#custom-captcha-solving)\n */\n captchaInputSelector?: string;\n context?: BrowserSettings.Context;\n /**\n * The uploaded Extension ID. See\n * [Upload Extension](/reference/api/upload-an-extension).\n */\n extensionId?: string;\n /**\n * Enable or disable ignoring of certificate errors in the browser. Defaults to\n * `false`, so TLS certificate validation is enforced; set to `true` to ignore\n * certificate errors (for example, to reach hosts with expired or self-signed\n * certificates).\n */\n ignoreCertificateErrors?: boolean;\n /**\n * Enable or disable session logging. Defaults to `true`.\n */\n logSession?: boolean;\n /**\n * Operating system for stealth mode. Valid values: windows, mac, linux, mobile,\n * tablet\n */\n os?: 'windows' | 'mac' | 'linux' | 'mobile' | 'tablet';\n /**\n * Enable or disable session recording. Defaults to `true`.\n */\n recordSession?: boolean;\n /**\n * Enable or disable captcha solving in the browser. Defaults to `true`.\n */\n solveCaptchas?: boolean;\n /**\n=== client opts ===\n21: apiKey?: string | undefined;\n32: * Note that request timeouts are retried by default, so in a worst-case scenario you may wait\n33: * much longer than this timeout before the promise succeeds or fails.\n37: timeout?: number | undefined;\n60: maxRetries?: number | undefined;\n81: apiKey: string;\n86: * @param {string | undefined} [opts.apiKey=process.env['BROWSERBASE_API_KEY'] ?? undefined]\n88: * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n91: * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n95: constructor({ baseURL, apiKey, ...opts }?: ClientOptions);\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-adb8b8af71b2dcc9",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Good. Now install puppeteer-core to drive the browser over CDP. Verify no Chromium download.
cd /sandbox/repo && timeout 300 npm i puppeteer-core@23 2>&1 | tail -4; du -sh node_modules; ls ~/.cache/puppeteer 2>&1 | head -3
To address all issues (including breaking changes), run:
To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details. 53M node_modules ls: cannot access '/sandbox/.cache/puppeteer': No such file or directory
Recorded tool call
{
"type": "tool_call",
"seq": 39,
"ts": "2026-10-15T09:34:11.791Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && timeout 300 npm i puppeteer-core@23 2>&1 | tail -4; du -sh node_modules; ls ~/.cache/puppeteer 2>&1 | head -3"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-8a73565d16d31d31",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 40,
"ts": "2026-10-15T09:34:26.988Z",
"turn": 1,
"output": {
"content": [
{
"text": "To address all issues (including breaking changes), run:\n npm audit fix --force\n\nRun `npm audit` for details.\n53M\tnode_modules\nls: cannot access '/sandbox/.cache/puppeteer': No such file or directory\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-8a73565d16d31d31",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
No browser downloaded — good, puppeteer-core is just a client.
Now write the example. Keep it simple:
src/hello-browserbase.mjs(or .js with ESM since package.json type? npm init -y gives no "type". I'll use .mjs or set type module). Let's set the package.json properly.
Example: create a session, connect via puppeteer.connect over connectUrl, navigate to a page, grab title + screenshot, end session. Also print debuggerUrl.
Also maybe a second script showing the pure SDK-only path (no browser driving): list sessions / get session replays/logs. Actually keep it to one main script + maybe a small "sdk-only" script that works without any CDP (list projects/sessions) — useful for verifying credentials quickly.
Let me write:
- README.md
- .env.example
- src/check-credentials.mjs — pure SDK, lists projects & recent sessions (safe, no billing)
- src/scrape-example.mjs — main quickstart
Then run the credential check to confirm blocked state (401 without key). That's a fast command.
Let me write files.
No blockers on network/registry. Building the example now.
File edits
1 file
Writtenpackage.jsonView changes
/sandbox/repo/package.json
Written content · previous contents were not recorded
{"name": "browserbase-hello-world","version": "1.0.0","private": true,"type": "module","description": "Minimal Browserbase quickstart: create a hosted browser session, drive it over CDP, grab a screenshot.","scripts": {"check": "node src/check-credentials.mjs","scrape": "node src/scrape-example.mjs"},"dependencies": {"@browserbasehq/sdk": "^2.22.0","puppeteer-core": "^23.11.1"}}
Source: write · chatcmpl-tool-a658bffa943b2a6d
Recorded tool call
{
"type": "tool_call",
"seq": 44,
"ts": "2026-10-15T09:34:35.831Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/package.json",
"content": "{\n \"name\": \"browserbase-hello-world\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"description\": \"Minimal Browserbase quickstart: create a hosted browser session, drive it over CDP, grab a screenshot.\",\n \"scripts\": {\n \"check\": \"node src/check-credentials.mjs\",\n \"scrape\": \"node src/scrape-example.mjs\"\n },\n \"dependencies\": {\n \"@browserbasehq/sdk\": \"^2.22.0\",\n \"puppeteer-core\": \"^23.11.1\"\n }\n}\n"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a658bffa943b2a6d",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 45,
"ts": "2026-10-15T09:34:35.831Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 430 bytes to /sandbox/repo/package.json",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a658bffa943b2a6d",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Now write src/check-credentials.mjs and src/scrape-example.mjs.
File edits
1 file
Writtensrc/check-credentials.mjsView changes
/sandbox/repo/src/check-credentials.mjs
Written content · previous contents were not recorded
// Credential smoke test — talks only to the Browserbase REST API.// Creates nothing, costs nothing. Run this first.//// export BROWSERBASE_API_KEY=... (and optionally BROWSERBASE_PROJECT_ID)// npm run checkimport { Browserbase } from "@browserbasehq/sdk";const apiKey = process.env.BROWSERBASE_API_KEY;const projectId = process.env.BROWSERBASE_PROJECT_ID;if (!apiKey) {console.error("Missing BROWSERBASE_API_KEY.");console.error("Get one at https://www.browserbase.com/settings");process.exit(1);}const browserbase = new Browserbase({ apiKey, projectId });try {const project = await browserbase.projects.retrieve(projectId);console.log(`Connected to project: ${project.name} (${project.id})`);console.log(` default browser lifetime: ${project.defaultTimeout}s`);const sessions = await browserbase.sessions.list({ limit: 5 });console.log(`\nLast ${sessions.length} session(s):`);for (const s of sessions) {console.log(` ${s.id} ${s.status} started=${s.startedAt} region=${s.region}`);}if (sessions.length === 0) console.log(" (none yet)");} catch (err) {console.error("Browserbase API call failed:", err.status, err.message);process.exit(1);}
Source: write · chatcmpl-tool-aba8ef6a144a2e3f
Recorded tool call
{
"type": "tool_call",
"seq": 48,
"ts": "2026-10-15T09:34:43.939Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/src/check-credentials.mjs",
"content": "// Credential smoke test — talks only to the Browserbase REST API.\n// Creates nothing, costs nothing. Run this first.\n//\n// export BROWSERBASE_API_KEY=... (and optionally BROWSERBASE_PROJECT_ID)\n// npm run check\n\nimport { Browserbase } from \"@browserbasehq/sdk\";\n\nconst apiKey = process.env.BROWSERBASE_API_KEY;\nconst projectId = process.env.BROWSERBASE_PROJECT_ID;\n\nif (!apiKey) {\n console.error(\"Missing BROWSERBASE_API_KEY.\");\n console.error(\"Get one at https://www.browserbase.com/settings\");\n process.exit(1);\n}\n\nconst browserbase = new Browserbase({ apiKey, projectId });\n\ntry {\n const project = await browserbase.projects.retrieve(projectId);\n console.log(`Connected to project: ${project.name} (${project.id})`);\n console.log(` default browser lifetime: ${project.defaultTimeout}s`);\n\n const sessions = await browserbase.sessions.list({ limit: 5 });\n console.log(`\\nLast ${sessions.length} session(s):`);\n for (const s of sessions) {\n console.log(` ${s.id} ${s.status} started=${s.startedAt} region=${s.region}`);\n }\n if (sessions.length === 0) console.log(\" (none yet)\");\n} catch (err) {\n console.error(\"Browserbase API call failed:\", err.status, err.message);\n process.exit(1);\n}\n"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-aba8ef6a144a2e3f",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 49,
"ts": "2026-10-15T09:34:43.939Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 1219 bytes to /sandbox/repo/src/check-credentials.mjs",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-aba8ef6a144a2e3f",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Let me verify projects.retrieve signature and whether it requires projectId as arg. Check resources/projects.d.ts and sessions.list params.
cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '1,60p' resources/projects.d.ts; echo "=== list params ==="; sed -n '/export interface SessionListParams/,/^}/p' resources/sessions/sessions.d.ts
import { APIResource } from "../resource.js";
import { APIResource } from "../resource.js";
import * as Core from "../core.js";
export declare class Projects extends APIResource {
/**
* Get a Project
*/
retrieve(id: string, options?: Core.RequestOptions): Core.APIPromise<Project>;
/**
* List Projects
*/
list(options?: Core.RequestOptions): Core.APIPromise<ProjectListResponse>;
/**
* Get Project Usage
*/
usage(id: string, options?: Core.RequestOptions): Core.APIPromise<ProjectUsage>;
}
export interface Project {
id: string;
/**
* The maximum number of sessions that this project can run concurrently.
*/
concurrency: number;
createdAt: string;
defaultTimeout: number;
name: string;
ownerId: string;
updatedAt: string;
}
export interface ProjectUsage {
browserMinutes: number;
proxyBytes: number;
}
export type ProjectListResponse = Array<Project>;
export declare namespace Projects {
export { type Project as Project, type ProjectUsage as ProjectUsage, type ProjectListResponse as ProjectListResponse, };
}
//# sourceMappingURL=projects.d.ts.map=== list params ===
export interface SessionListParams {
/**
* Query sessions by user metadata. See
* [Querying Sessions by User Metadata](/features/sessions#querying-sessions-by-user-metadata)
* for the schema of this query.
*/
q?: string;
status?: 'PENDING' | 'RUNNING' | 'ERROR' | 'TIMED_OUT' | 'COMPLETED';
}
Recorded tool call
{
"type": "tool_call",
"seq": 52,
"ts": "2026-10-15T09:34:48.791Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '1,60p' resources/projects.d.ts; echo \"=== list params ===\"; sed -n '/export interface SessionListParams/,/^}/p' resources/sessions/sessions.d.ts"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-98bb4b88299a9681",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 53,
"ts": "2026-10-15T09:34:48.791Z",
"turn": 1,
"output": {
"content": [
{
"text": "import { APIResource } from \"../resource.js\";\nimport * as Core from \"../core.js\";\nexport declare class Projects extends APIResource {\n /**\n * Get a Project\n */\n retrieve(id: string, options?: Core.RequestOptions): Core.APIPromise<Project>;\n /**\n * List Projects\n */\n list(options?: Core.RequestOptions): Core.APIPromise<ProjectListResponse>;\n /**\n * Get Project Usage\n */\n usage(id: string, options?: Core.RequestOptions): Core.APIPromise<ProjectUsage>;\n}\nexport interface Project {\n id: string;\n /**\n * The maximum number of sessions that this project can run concurrently.\n */\n concurrency: number;\n createdAt: string;\n defaultTimeout: number;\n name: string;\n ownerId: string;\n updatedAt: string;\n}\nexport interface ProjectUsage {\n browserMinutes: number;\n proxyBytes: number;\n}\nexport type ProjectListResponse = Array<Project>;\nexport declare namespace Projects {\n export { type Project as Project, type ProjectUsage as ProjectUsage, type ProjectListResponse as ProjectListResponse, };\n}\n//# sourceMappingURL=projects.d.ts.map=== list params ===\nexport interface SessionListParams {\n /**\n * Query sessions by user metadata. See\n * [Querying Sessions by User Metadata](/features/sessions#querying-sessions-by-user-metadata)\n * for the schema of this query.\n */\n q?: string;\n status?: 'PENDING' | 'RUNNING' | 'ERROR' | 'TIMED_OUT' | 'COMPLETED';\n}\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-98bb4b88299a9681",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
SessionListParams has no limit. Fix that. Also projects.retrieve requires an id — if no project id env, list projects and take first. Let me fix the check script.
File edits
1 file
Writtensrc/check-credentials.mjsView changes
/sandbox/repo/src/check-credentials.mjs
Written content · previous contents were not recorded
// Credential smoke test — talks only to the Browserbase REST API.// Creates nothing, costs nothing. Run this first.//// export BROWSERBASE_API_KEY=... (and optionally BROWSERBASE_PROJECT_ID)// npm run checkimport { Browserbase } from "@browserbasehq/sdk";const apiKey = process.env.BROWSERBASE_API_KEY;if (!apiKey) {console.error("Missing BROWSERBASE_API_KEY.");console.error("Get one at https://www.browserbase.com/settings");process.exit(1);}const browserbase = new Browserbase({apiKey,projectId: process.env.BROWSERBASE_PROJECT_ID, // optional; inferred from the key});try {// Resolve a project id if one wasn't supplied.const projects = await browserbase.projects.list();const project =projects.find((p) => p.id === process.env.BROWSERBASE_PROJECT_ID) ?? projects[0];if (!project) {console.error("API key is valid but no project was found.");process.exit(1);}console.log(`Connected to project: ${project.name} (${project.id})`);console.log(` concurrency: ${project.concurrency} default lifetime: ${project.defaultTimeout}s`);const usage = await browserbase.projects.usage(project.id);console.log(` used: ${usage.browserMinutes} browser-minutes, ${usage.proxyBytes} proxy bytes`);const sessions = await browserbase.sessions.list({ status: "COMPLETED" });const recent = sessions.slice(0, 5);console.log(`\nRecent completed session(s): ${recent.length}`);for (const s of recent) {console.log(` ${s.id} ${s.status} started=${s.startedAt} region=${s.region}`);}if (recent.length === 0) console.log(" (none yet — run `npm run scrape` to create one)");} catch (err) {console.error("Browserbase API call failed:", err.status ?? "", err.message);process.exit(1);}
Source: write · chatcmpl-tool-a4d1159e198738f7
Recorded tool call
{
"type": "tool_call",
"seq": 56,
"ts": "2026-10-15T09:34:55.741Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/src/check-credentials.mjs",
"content": "// Credential smoke test — talks only to the Browserbase REST API.\n// Creates nothing, costs nothing. Run this first.\n//\n// export BROWSERBASE_API_KEY=... (and optionally BROWSERBASE_PROJECT_ID)\n// npm run check\n\nimport { Browserbase } from \"@browserbasehq/sdk\";\n\nconst apiKey = process.env.BROWSERBASE_API_KEY;\n\nif (!apiKey) {\n console.error(\"Missing BROWSERBASE_API_KEY.\");\n console.error(\"Get one at https://www.browserbase.com/settings\");\n process.exit(1);\n}\n\nconst browserbase = new Browserbase({\n apiKey,\n projectId: process.env.BROWSERBASE_PROJECT_ID, // optional; inferred from the key\n});\n\ntry {\n // Resolve a project id if one wasn't supplied.\n const projects = await browserbase.projects.list();\n const project =\n projects.find((p) => p.id === process.env.BROWSERBASE_PROJECT_ID) ?? projects[0];\n\n if (!project) {\n console.error(\"API key is valid but no project was found.\");\n process.exit(1);\n }\n\n console.log(`Connected to project: ${project.name} (${project.id})`);\n console.log(` concurrency: ${project.concurrency} default lifetime: ${project.defaultTimeout}s`);\n\n const usage = await browserbase.projects.usage(project.id);\n console.log(` used: ${usage.browserMinutes} browser-minutes, ${usage.proxyBytes} proxy bytes`);\n\n const sessions = await browserbase.sessions.list({ status: \"COMPLETED\" });\n const recent = sessions.slice(0, 5);\n console.log(`\\nRecent completed session(s): ${recent.length}`);\n for (const s of recent) {\n console.log(` ${s.id} ${s.status} started=${s.startedAt} region=${s.region}`);\n }\n if (recent.length === 0) console.log(\" (none yet — run `npm run scrape` to create one)\");\n} catch (err) {\n console.error(\"Browserbase API call failed:\", err.status ?? \"\", err.message);\n process.exit(1);\n}\n"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a4d1159e198738f7",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 57,
"ts": "2026-10-15T09:34:55.741Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 1783 bytes to /sandbox/repo/src/check-credentials.mjs",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a4d1159e198738f7",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Now the main example. Use puppeteer-core connect with browserWSEndpoint = connectUrl. Handle errors, end session in finally.
Keep it simple and short.
File edits
1 file
Writtensrc/scrape-example.mjsView changes
/sandbox/repo/src/scrape-example.mjs
Written content · previous contents were not recorded
// Browserbase quickstart: spin up a hosted browser, drive it over CDP,// save a screenshot, then end the session.//// export BROWSERBASE_API_KEY=...// npm run scrape -- https://news.ycombinator.comimport { writeFile } from "node:fs/promises";import path from "node:path";import { Browserbase } from "@browserbasehq/sdk";import puppeteer from "puppeteer-core";const targetUrl = process.argv[2] ?? "https://example.com";if (!process.env.BROWSERBASE_API_KEY) {console.error("Missing BROWSERBASE_API_KEY — see https://www.browserbase.com/settings");process.exit(1);}const browserbase = new Browserbase({apiKey: process.env.BROWSERBASE_API_KEY,projectId: process.env.BROWSERBASE_PROJECT_ID, // optional});// 1. Create a hosted browser session (this is what you pay for).const session = await browserbase.sessions.create({api_timeout: 120, // auto-end after 2 min even if we crashbrowserSettings: { blockAds: true },userMetadata: { example: "hello-browserbase" },});console.log(`Session ${session.id} → ${session.status}`);console.log(` live view: ${(await browserbase.sessions.debug(session.id)).debuggerFullscreenUrl}`);let browser;try {// 2. Attach Puppeteer to the remote browser. No local Chromium is downloaded.browser = await puppeteer.connect({ browserWSEndpoint: session.connectUrl });const page = await browser.newPage();await page.setViewport({ width: 1280, height: 800 });await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 60_000 });const title = await page.title();const heading = await page.$eval("h1", (el) => el.textContent?.trim()).catch(() => "(no <h1>)");const links = await page.$$eval("a", (els) => els.length);console.log(`\n title: ${title}`);console.log(` <h1>: ${heading}`);console.log(` links: ${links}`);const shotPath = path.join("out", "screenshot.png");await writeFile(shotPath, await page.screenshot({ fullPage: false }));console.log(`\nSaved ${shotPath}`);} finally {// 3. Always disconnect and end the session, or you keep paying for it.if (browser) await browser.disconnect().catch(() => {});await browserbase.sessions.update(session.id, { status: "REQUEST_RELEASE" });console.log(`Session ${session.id} released.`);}
Source: write · chatcmpl-tool-bf9401fc7c3d9bae
Recorded tool call
{
"type": "tool_call",
"seq": 60,
"ts": "2026-10-15T09:35:06.529Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/src/scrape-example.mjs",
"content": "// Browserbase quickstart: spin up a hosted browser, drive it over CDP,\n// save a screenshot, then end the session.\n//\n// export BROWSERBASE_API_KEY=...\n// npm run scrape -- https://news.ycombinator.com\n\nimport { writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Browserbase } from \"@browserbasehq/sdk\";\nimport puppeteer from \"puppeteer-core\";\n\nconst targetUrl = process.argv[2] ?? \"https://example.com\";\n\nif (!process.env.BROWSERBASE_API_KEY) {\n console.error(\"Missing BROWSERBASE_API_KEY — see https://www.browserbase.com/settings\");\n process.exit(1);\n}\n\nconst browserbase = new Browserbase({\n apiKey: process.env.BROWSERBASE_API_KEY,\n projectId: process.env.BROWSERBASE_PROJECT_ID, // optional\n});\n\n// 1. Create a hosted browser session (this is what you pay for).\nconst session = await browserbase.sessions.create({\n api_timeout: 120, // auto-end after 2 min even if we crash\n browserSettings: { blockAds: true },\n userMetadata: { example: \"hello-browserbase\" },\n});\n\nconsole.log(`Session ${session.id} → ${session.status}`);\nconsole.log(` live view: ${(await browserbase.sessions.debug(session.id)).debuggerFullscreenUrl}`);\n\nlet browser;\ntry {\n // 2. Attach Puppeteer to the remote browser. No local Chromium is downloaded.\n browser = await puppeteer.connect({ browserWSEndpoint: session.connectUrl });\n\n const page = await browser.newPage();\n await page.setViewport({ width: 1280, height: 800 });\n await page.goto(targetUrl, { waitUntil: \"domcontentloaded\", timeout: 60_000 });\n\n const title = await page.title();\n const heading = await page\n .$eval(\"h1\", (el) => el.textContent?.trim())\n .catch(() => \"(no <h1>)\");\n const links = await page.$$eval(\"a\", (els) => els.length);\n\n console.log(`\\n title: ${title}`);\n console.log(` <h1>: ${heading}`);\n console.log(` links: ${links}`);\n\n const shotPath = path.join(\"out\", \"screenshot.png\");\n await writeFile(shotPath, await page.screenshot({ fullPage: false }));\n console.log(`\\nSaved ${shotPath}`);\n} finally {\n // 3. Always disconnect and end the session, or you keep paying for it.\n if (browser) await browser.disconnect().catch(() => {});\n await browserbase.sessions.update(session.id, { status: \"REQUEST_RELEASE\" });\n console.log(`Session ${session.id} released.`);\n}\n"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-bf9401fc7c3d9bae",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 61,
"ts": "2026-10-15T09:35:06.529Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 2298 bytes to /sandbox/repo/src/scrape-example.mjs",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-bf9401fc7c3d9bae",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Verify SessionUpdateParams status value 'REQUEST_RELEASE'.
cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '/export interface SessionUpdateParams/,/^}/p' resources/sessions/sessions.d.ts
export interface SessionUpdateParams {
export interface SessionUpdateParams {
/**
* Set to `REQUEST_RELEASE` to request that the session complete. Use before
* session's timeout to avoid additional charges.
*/
status: 'REQUEST_RELEASE';
/**
* The Project ID. Can be found in
* [Settings](https://www.browserbase.com/settings). Optional - if not provided,
* the project will be inferred from the API key.
*/
projectId?: string;
}
Recorded tool call
{
"type": "tool_call",
"seq": 64,
"ts": "2026-10-15T09:35:09.042Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/node_modules/@browserbasehq/sdk && sed -n '/export interface SessionUpdateParams/,/^}/p' resources/sessions/sessions.d.ts"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-8460dc9bb4d02f60",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 65,
"ts": "2026-10-15T09:35:09.042Z",
"turn": 1,
"output": {
"content": [
{
"text": "export interface SessionUpdateParams {\n /**\n * Set to `REQUEST_RELEASE` to request that the session complete. Use before\n * session's timeout to avoid additional charges.\n */\n status: 'REQUEST_RELEASE';\n /**\n * The Project ID. Can be found in\n * [Settings](https://www.browserbase.com/settings). Optional - if not provided,\n * the project will be inferred from the API key.\n */\n projectId?: string;\n}\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-8460dc9bb4d02f60",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Good. Now syntax-check both scripts (they'll fail at runtime on missing key, but check syntax with node --check).
Also add .env.example and README. Then run npm run check to demonstrate blocked state.
cd /sandbox/repo && node --check src/check-credentials.mjs && node --check src/scrape-example.mjs && echo "syntax OK"
syntax OK
syntax OK
Recorded tool call
{
"type": "tool_call",
"seq": 68,
"ts": "2026-10-15T09:35:10.921Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && node --check src/check-credentials.mjs && node --check src/scrape-example.mjs && echo \"syntax OK\""
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-baa28b2712b039e5",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 69,
"ts": "2026-10-15T09:35:10.921Z",
"turn": 1,
"output": {
"content": [
{
"text": "syntax OK\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-baa28b2712b039e5",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Now .env.example and README, then run the check to show blocked state.
File edits
1 file
Written.env.exampleView changes
/sandbox/repo/.env.example
Written content · previous contents were not recorded
# Required. https://www.browserbase.com/settingsBROWSERBASE_API_KEY=# Optional — inferred from the API key if omitted.BROWSERBASE_PROJECT_ID=
Source: write · chatcmpl-tool-acb392be6602af15
Recorded tool call
{
"type": "tool_call",
"seq": 72,
"ts": "2026-10-15T09:35:13.073Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/.env.example",
"content": "# Required. https://www.browserbase.com/settings\nBROWSERBASE_API_KEY=\n\n# Optional — inferred from the API key if omitted.\nBROWSERBASE_PROJECT_ID=\n"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-acb392be6602af15",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 73,
"ts": "2026-10-15T09:35:13.073Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 146 bytes to /sandbox/repo/.env.example",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-acb392be6602af15",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Now README, then run the check script to show the blocked state.
File edits
1 file
WrittenREADME.mdView changes
/sandbox/repo/README.md
Written content · previous contents were not recorded
# Browserbase hello worldMinimal hosted-browser example using the official Node SDK (`@browserbasehq/sdk`)plus `puppeteer-core` as a CDP client. **No local Chromium, no Docker, no localservice stack** — the browser runs on Browserbase's infrastructure and youconnect to it over a WebSocket.## Setup```bashnpm installexport BROWSERBASE_API_KEY=... # https://www.browserbase.com/settings# optional: export BROWSERBASE_PROJECT_ID=...```## Run```bashnpm run check # REST-only smoke test; creates nothing, costs nothingnpm run scrape # scrape https://example.comnpm run scrape -- https://news.ycombinator.com````scrape` creates a session, prints the live debugger URL, reads the pagetitle / `<h1>` / link count, writes `out/screenshot.png`, then releases thesession.## Files| File | What it does || --- | --- || `src/check-credentials.mjs` | Lists projects, usage, and recent sessions. Pure REST, zero cost. || `src/scrape-example.mjs` | The actual quickstart: create → connect → navigate → screenshot → release. |## Cost control (important)- You are billed for **browser minutes** while a session is alive.- Every session here is created with `api_timeout: 120`, so it self-destructsafter 2 minutes even if the script crashes.- The `finally` block calls `sessions.update(id, { status: "REQUEST_RELEASE" })`on every path. Do not skip this in real code.- `browserSettings.blockAds: true` reduces page weight and proxy bytes.## Notes- `session.connectUrl` is the CDP WebSocket endpoint; `puppeteer.connect()`attaches to it. Playwright and Selenium work the same way(`seleniumRemoteUrl`).- `sessions.debug(id)` returns live-view URLs — open one in a browser to watchthe session run in real time.- Sessions are region-pinned (`us-west-2`, `us-east-1`, `eu-central-1`,`ap-southeast-1`). Pick one near your workload to cut latency.
Source: write · chatcmpl-tool-aedc3d99983f143c
Recorded tool call
{
"type": "tool_call",
"seq": 76,
"ts": "2026-10-15T09:35:21.049Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/README.md",
"content": "# Browserbase hello world\n\nMinimal hosted-browser example using the official Node SDK (`@browserbasehq/sdk`)\nplus `puppeteer-core` as a CDP client. **No local Chromium, no Docker, no local\nservice stack** — the browser runs on Browserbase's infrastructure and you\nconnect to it over a WebSocket.\n\n## Setup\n\n```bash\nnpm install\nexport BROWSERBASE_API_KEY=... # https://www.browserbase.com/settings\n# optional: export BROWSERBASE_PROJECT_ID=...\n```\n\n## Run\n\n```bash\nnpm run check # REST-only smoke test; creates nothing, costs nothing\nnpm run scrape # scrape https://example.com\nnpm run scrape -- https://news.ycombinator.com\n```\n\n`scrape` creates a session, prints the live debugger URL, reads the page\ntitle / `<h1>` / link count, writes `out/screenshot.png`, then releases the\nsession.\n\n## Files\n\n| File | What it does |\n| --- | --- |\n| `src/check-credentials.mjs` | Lists projects, usage, and recent sessions. Pure REST, zero cost. |\n| `src/scrape-example.mjs` | The actual quickstart: create → connect → navigate → screenshot → release. |\n\n## Cost control (important)\n\n- You are billed for **browser minutes** while a session is alive.\n- Every session here is created with `api_timeout: 120`, so it self-destructs\n after 2 minutes even if the script crashes.\n- The `finally` block calls `sessions.update(id, { status: \"REQUEST_RELEASE\" })`\n on every path. Do not skip this in real code.\n- `browserSettings.blockAds: true` reduces page weight and proxy bytes.\n\n## Notes\n\n- `session.connectUrl` is the CDP WebSocket endpoint; `puppeteer.connect()`\n attaches to it. Playwright and Selenium work the same way\n (`seleniumRemoteUrl`).\n- `sessions.debug(id)` returns live-view URLs — open one in a browser to watch\n the session run in real time.\n- Sessions are region-pinned (`us-west-2`, `us-east-1`, `eu-central-1`,\n `ap-southeast-1`). Pick one near your workload to cut latency.\n"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-aedc3d99983f143c",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 77,
"ts": "2026-10-15T09:35:21.049Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 1940 bytes to /sandbox/repo/README.md",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-aedc3d99983f143c",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Now run the check to demonstrate blocked state, and verify the SDK loads (import works) without network. Also add out/ to gitignore? .gitignore doesn't have out/. Let me add it.
Run npm run check — should fail with missing key message.
cd /sandbox/repo && printf '\n# Local output\nout/\n.env\n' >> .gitignore && timeout 60 npm run check 2>&1 | tail -5; echo "exit=$?"
> browserbase-hello-world@1.0.0 check
> browserbase-hello-world@1.0.0 check > node src/check-credentials.mjs Missing BROWSERBASE_API_KEY. Get one at https://www.browserbase.com/settings exit=0
Recorded tool call
{
"type": "tool_call",
"seq": 80,
"ts": "2026-10-15T09:35:24.254Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && printf '\\n# Local output\\nout/\\n.env\\n' >> .gitignore && timeout 60 npm run check 2>&1 | tail -5; echo \"exit=$?\""
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-87b01268fe1b3329",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 81,
"ts": "2026-10-15T09:35:24.586Z",
"turn": 1,
"output": {
"content": [
{
"text": "> browserbase-hello-world@1.0.0 check\n> node src/check-credentials.mjs\n\nMissing BROWSERBASE_API_KEY.\nGet one at https://www.browserbase.com/settings\nexit=0\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-87b01268fe1b3329",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Blocked as expected (no credentials). Let me verify the import path works at least (SDK loads), by a quick node -e import test. And verify that with a fake key the API returns 401 — proving the code path reaches the API correctly. That's a fast, safe command.
cd /sandbox/repo && BROWSERBASE_API_KEY=fake-key-test timeout 60 node src/check-credentials.mjs 2>&1 | tail -3; echo "---scrape guard---"; BROWSERBASE_API_KEY= timeout 30 node src/scrape-example.mjs 2>&1 | tail -2
Browserbase API call failed: 401 401 Unauthorized
Browserbase API call failed: 401 401 Unauthorized ---scrape guard--- Missing BROWSERBASE_API_KEY — see https://www.browserbase.com/settings
Recorded tool call
{
"type": "tool_call",
"seq": 84,
"ts": "2026-10-15T09:35:27.587Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && BROWSERBASE_API_KEY=fake-key-test timeout 60 node src/check-credentials.mjs 2>&1 | tail -3; echo \"---scrape guard---\"; BROWSERBASE_API_KEY= timeout 30 node src/scrape-example.mjs 2>&1 | tail -2"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a5c2fd8d1b023587",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 85,
"ts": "2026-10-15T09:35:28.259Z",
"turn": 1,
"output": {
"content": [
{
"text": "Browserbase API call failed: 401 401 Unauthorized\n---scrape guard---\nMissing BROWSERBASE_API_KEY — see https://www.browserbase.com/settings\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-a5c2fd8d1b023587",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Both paths behave correctly: with a bogus key we reach the real API and get a clean 401 handled by the error path. That's as far as I can verify without real credentials.
Let me do a final check on the repo state and git status.
cd /sandbox/repo && git status --short && echo "---" && find . -path ./node_modules -prune -o -type f -print | sort
M .gitignore
M .gitignore ?? .env.example ?? README.md ?? package-lock.json ?? package.json ?? src/ --- ./.env.example ./.git/COMMIT_EDITMSG ./.git/HEAD ./.git/config ./.git/description ./.git/hooks/applypatch-msg.sample ./.git/hooks/commit-msg.sample ./.git/hooks/fsmonitor-watchman.sample ./.git/hooks/post-update.sample ./.git/hooks/pre-applypatch.sample ./.git/hooks/pre-commit.sample ./.git/hooks/pre-merge-commit.sample ./.git/hooks/pre-push.sample ./.git/hooks/pre-rebase.sample ./.git/hooks/pre-receive.sample ./.git/hooks/prepare-commit-msg.sample ./.git/hooks/push-to-checkout.sample ./.git/hooks/sendemail-validate.sample ./.git/hooks/update.sample ./.git/index ./.git/info/exclude ./.git/logs/HEAD ./.git/logs/refs/heads/main ./.git/objects/0b/44f19b88e3f1dcfc78a8e58d7fd342444c283a ./.git/objects/9e/bf5fbd2cef623cbb4d140d0c660320192c4977 ./.git/objects/f0/6033644e276829720c3a94968aad46a71d2331 ./.git/refs/heads/main ./.gitignore ./README.md ./package-lock.json ./package.json ./src/check-credentials.mjs ./src/scrape-example.mjs
Recorded tool call
{
"type": "tool_call",
"seq": 88,
"ts": "2026-10-15T09:35:31.963Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && git status --short && echo \"---\" && find . -path ./node_modules -prune -o -type f -print | sort"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-8c041c5fba8dc16a",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 89,
"ts": "2026-10-15T09:35:31.963Z",
"turn": 1,
"output": {
"content": [
{
"text": " M .gitignore\n?? .env.example\n?? README.md\n?? package-lock.json\n?? package.json\n?? src/\n---\n./.env.example\n./.git/COMMIT_EDITMSG\n./.git/HEAD\n./.git/config\n./.git/description\n./.git/hooks/applypatch-msg.sample\n./.git/hooks/commit-msg.sample\n./.git/hooks/fsmonitor-watchman.sample\n./.git/hooks/post-update.sample\n./.git/hooks/pre-applypatch.sample\n./.git/hooks/pre-commit.sample\n./.git/hooks/pre-merge-commit.sample\n./.git/hooks/pre-push.sample\n./.git/hooks/pre-rebase.sample\n./.git/hooks/pre-receive.sample\n./.git/hooks/prepare-commit-msg.sample\n./.git/hooks/push-to-checkout.sample\n./.git/hooks/sendemail-validate.sample\n./.git/hooks/update.sample\n./.git/index\n./.git/info/exclude\n./.git/logs/HEAD\n./.git/logs/refs/heads/main\n./.git/objects/0b/44f19b88e3f1dcfc78a8e58d7fd342444c283a\n./.git/objects/9e/bf5fbd2cef623cbb4d140d0c660320192c4977\n./.git/objects/f0/6033644e276829720c3a94968aad46a71d2331\n./.git/refs/heads/main\n./.gitignore\n./README.md\n./package-lock.json\n./package.json\n./src/check-credentials.mjs\n./src/scrape-example.mjs\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-8c041c5fba8dc16a",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
I should give the final summary: what I built, pricing, manageability, and where I got blocked.
Let me be accurate about pricing. Browserbase pricing (as of my knowledge): Free tier with $0 (limited browser hours, 1 concurrent session), Hobby plan ~$39/mo (100 browser hours, 3 concurrent), Startup ~$149/mo (1,000 hours, 20 concurrent), Scale ~$499/mo (5,000 hours, 100 concurrent), plus Enterprise. Overage ~$0.45/browser hour? Let me be careful — I shouldn't state precise numbers I'm unsure about. I verified usage API exposes browserMinutes and proxyBytes, which confirms billing dimensions. I should state the dimensions confidently and be hedged on exact dollar figures, recommending they check the pricing page.
Actually, let me check if I can fetch the pricing page to be accurate. Network works. Let me try quickly.
cd /tmp && timeout 30 curl -sL https://www.browserbase.com/pricing -o p.html -w "%{http_code} %{size_download}\n"; python3 - <<'EOF'
import re,html
t=open('/tmp/p.html',encoding='utf-8',errors='ignore').read()
t=re.sub(r'<script.*?</script>','',t,flags=re.S)
t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=html.unescape(re.sub(r'<[^>]+>',' ',t))
t=re.sub(r'\s+',' ',t)
for m in re.finditer(r'(\$\d[\d,]*)', t):
print(t[max(0,m.start()-120):m.end()+160].strip())
print('---')
EOF200 283453
200 283453 Browserbase Pricing: Free, $20, $99, or Custom | Browserbase Skip to content Browserbase Navigation Platform Primitives Browsers Cloud browsers for your agent to use the web Agents Scale full --- Browserbase Pricing: Free, $20, $99, or Custom | Browserbase Skip to content Browserbase Navigation Platform Primitives Browsers Cloud browsers for your agent to use the web Agents Scale fully man --- no caps or throttling as you build, billed at your plan’s rate. And as always, you can get started for free. Free Plan $0/mo Get started with Browserbase. Explore and prototype ideas. Infrastructure 3 concurrent browsers 1 browser hour 3 Agent runs included 1,000 Search calls 1,00 --- wsers 1 browser hour 3 Agent runs included 1,000 Search calls 1,000 Fetch calls 15 minutes /session Capabilities Models $5 in tokens Runtime included Start for free Developer Plan $20/mo Build and test real workflows. Prepare for production. Infrastructure 25 concurrent browsers 10 --- s 1,000 Fetch calls 15 minutes /session Capabilities Models $5 in tokens Runtime included Start for free Developer Plan $20/mo Build and test real workflows. Prepare for production. Infrastructure 25 concurrent browsers 100 browser hours then $0.12/browser hr 15 Agent runs included --- /mo Build and test real workflows. Prepare for production. Infrastructure 25 concurrent browsers 100 browser hours then $0.12/browser hr 15 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 1,000 Fetch calls then $1/1k calls with Extract & Prox --- structure 25 concurrent browsers 100 browser hours then $0.12/browser hr 15 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 1,000 Fetch calls then $1/1k calls with Extract & Proxy pricing below 1 GB of proxies Then $12/GB Capabilities Models --- er hr 15 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 1,000 Fetch calls then $1/1k calls with Extract & Proxy pricing below 1 GB of proxies Then $12/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identity --- by default with more options 1,000 Fetch calls then $1/1k calls with Extract & Proxy pricing below 1 GB of proxies Then $12/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identity Auto captcha solving Get Developer MOST POPULAR Startup Plan $99/mo --- eway Market Price: Pay as you go Runtime included Identity Auto captcha solving Get Developer MOST POPULAR Startup Plan $99/mo Run in production with room to grow and scale usage. Infrastructure 100 concurrent browsers 500 browser hours then $0.10/browser hr 50 Agent runs included 1 --- 9/mo Run in production with room to grow and scale usage. Infrastructure 100 concurrent browsers 500 browser hours then $0.10/browser hr 50 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 10,000 Fetch calls then $0.5/1k calls with Extract & P --- tructure 100 concurrent browsers 500 browser hours then $0.10/browser hr 50 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 10,000 Fetch calls then $0.5/1k calls with Extract & Proxy pricing below 5 GB of proxies then $10/GB Capabilities Mode --- r hr 50 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 10,000 Fetch calls then $0.5/1k calls with Extract & Proxy pricing below 5 GB of proxies then $10/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identi --- default with more options 10,000 Fetch calls then $0.5/1k calls with Extract & Proxy pricing below 5 GB of proxies then $10/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identity Auto captcha solving Get Startup Scale Plan Custom Operate at scale --- tart for Free Get Developer Get Startup Contact Sales Infrastructure Concurrency 3 25 100 250+ Browser hours 1 100 then $0.12/browser hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - --- r Get Startup Contact Sales Infrastructure Concurrency 3 25 100 250+ Browser hours 1 100 then $0.12/browser hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1 --- rs 1 100 then $0.12/browser hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Se --- r hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 --- Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,00 --- s 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1 --- I 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Ex --- llel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Ext --- - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + E --- rallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-b --- 7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per --- based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Cus --- Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbas --- I 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbase Functions Yes --- 1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbase Functions Yes Yes Yes Yes Captcha --- Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbase Functions Yes Yes Yes Yes Captcha Solving No Yes Yes --- e Functions Yes Yes Yes Yes Captcha Solving No Yes Yes Yes Data Retention 7 days 30 days 30 days 30+ days Model Gateway $5 in models in tokens Pay as you go Market price Pay as you go Market price Pay as you go Market price Stealth Mode No Basic Basic Advanced Not sure which plan f ---
Recorded tool call
{
"type": "tool_call",
"seq": 92,
"ts": "2026-10-15T09:35:36.836Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 30 curl -sL https://www.browserbase.com/pricing -o p.html -w \"%{http_code} %{size_download}\\n\"; python3 - <<'EOF'\nimport re,html\nt=open('/tmp/p.html',encoding='utf-8',errors='ignore').read()\nt=re.sub(r'<script.*?</script>','',t,flags=re.S)\nt=re.sub(r'<style.*?</style>','',t,flags=re.S)\nt=html.unescape(re.sub(r'<[^>]+>',' ',t))\nt=re.sub(r'\\s+',' ',t)\nfor m in re.finditer(r'(\\$\\d[\\d,]*)', t):\n print(t[max(0,m.start()-120):m.end()+160].strip())\n print('---')\nEOF"
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-820d31a1ca2a5937",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 93,
"ts": "2026-10-15T09:35:38.596Z",
"turn": 1,
"output": {
"content": [
{
"text": "200 283453\nBrowserbase Pricing: Free, $20, $99, or Custom | Browserbase Skip to content Browserbase Navigation Platform Primitives Browsers Cloud browsers for your agent to use the web Agents Scale full\n---\nBrowserbase Pricing: Free, $20, $99, or Custom | Browserbase Skip to content Browserbase Navigation Platform Primitives Browsers Cloud browsers for your agent to use the web Agents Scale fully man\n---\nno caps or throttling as you build, billed at your plan’s rate. And as always, you can get started for free. Free Plan $0/mo Get started with Browserbase. Explore and prototype ideas. Infrastructure 3 concurrent browsers 1 browser hour 3 Agent runs included 1,000 Search calls 1,00\n---\nwsers 1 browser hour 3 Agent runs included 1,000 Search calls 1,000 Fetch calls 15 minutes /session Capabilities Models $5 in tokens Runtime included Start for free Developer Plan $20/mo Build and test real workflows. Prepare for production. Infrastructure 25 concurrent browsers 10\n---\ns 1,000 Fetch calls 15 minutes /session Capabilities Models $5 in tokens Runtime included Start for free Developer Plan $20/mo Build and test real workflows. Prepare for production. Infrastructure 25 concurrent browsers 100 browser hours then $0.12/browser hr 15 Agent runs included\n---\n/mo Build and test real workflows. Prepare for production. Infrastructure 25 concurrent browsers 100 browser hours then $0.12/browser hr 15 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 1,000 Fetch calls then $1/1k calls with Extract & Prox\n---\nstructure 25 concurrent browsers 100 browser hours then $0.12/browser hr 15 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 1,000 Fetch calls then $1/1k calls with Extract & Proxy pricing below 1 GB of proxies Then $12/GB Capabilities Models\n---\ner hr 15 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 1,000 Fetch calls then $1/1k calls with Extract & Proxy pricing below 1 GB of proxies Then $12/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identity\n---\nby default with more options 1,000 Fetch calls then $1/1k calls with Extract & Proxy pricing below 1 GB of proxies Then $12/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identity Auto captcha solving Get Developer MOST POPULAR Startup Plan $99/mo\n---\neway Market Price: Pay as you go Runtime included Identity Auto captcha solving Get Developer MOST POPULAR Startup Plan $99/mo Run in production with room to grow and scale usage. Infrastructure 100 concurrent browsers 500 browser hours then $0.10/browser hr 50 Agent runs included 1\n---\n9/mo Run in production with room to grow and scale usage. Infrastructure 100 concurrent browsers 500 browser hours then $0.10/browser hr 50 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 10,000 Fetch calls then $0.5/1k calls with Extract & P\n---\ntructure 100 concurrent browsers 500 browser hours then $0.10/browser hr 50 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 10,000 Fetch calls then $0.5/1k calls with Extract & Proxy pricing below 5 GB of proxies then $10/GB Capabilities Mode\n---\nr hr 50 Agent runs included 1,000 Search calls then $5/1k searches by default with more options 10,000 Fetch calls then $0.5/1k calls with Extract & Proxy pricing below 5 GB of proxies then $10/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identi\n---\ndefault with more options 10,000 Fetch calls then $0.5/1k calls with Extract & Proxy pricing below 5 GB of proxies then $10/GB Capabilities Models Model Gateway Market Price: Pay as you go Runtime included Identity Auto captcha solving Get Startup Scale Plan Custom Operate at scale\n---\ntart for Free Get Developer Get Startup Contact Sales Infrastructure Concurrency 3 25 100 250+ Browser hours 1 100 then $0.12/browser hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced -\n---\nr Get Startup Contact Sales Infrastructure Concurrency 3 25 100 250+ Browser hours 1 100 then $0.12/browser hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1\n---\nrs 1 100 then $0.12/browser hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Se\n---\nr hr 500 then $0.10/browser hr Usage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2\n---\nUsage-based Agent runs 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,00\n---\ns 3 15 50 Custom Search API 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1\n---\nI 1,000 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Ex\n---\nllel Fast - $5/1k for Parallel Advanced - $7/1k for Exa 1,000 - $1/1k for Parallel Fast - $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Ext\n---\n- $5/1k for Parallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + E\n---\nrallel Advanced - $7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-b\n---\n7/1k for Exa Usage-based Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per\n---\nbased Search RPS (per project) 2 2 2 Custom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Cus\n---\nCustom Fetch API 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbas\n---\nI 1,000 1,000 - $1/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbase Functions Yes\n---\n1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbase Functions Yes Yes Yes Yes Captcha\n---\nProxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract 10,000 - $0.5/1k calls - $4/1k w/ Proxies - $4/1k w/ Extract - $7/1k w/ Proxies + Extract Usage-based Fetch RPS (per project) 5 5 5 Custom Capabilities Runtime: Browserbase Functions Yes Yes Yes Yes Captcha Solving No Yes Yes\n---\ne Functions Yes Yes Yes Yes Captcha Solving No Yes Yes Yes Data Retention 7 days 30 days 30 days 30+ days Model Gateway $5 in models in tokens Pay as you go Market price Pay as you go Market price Pay as you go Market price Stealth Mode No Basic Basic Advanced Not sure which plan f\n---\n",
"type": "text"
}
]
},
"run_id": "cmv9ccaip02hf0itwgiara7pa",
"tool_id": "chatcmpl-tool-820d31a1ca2a5937",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
I have accurate live pricing. Let me write the final summary.
Note: Free plan is $0/mo with 1 browser hour, 3 concurrent browsers, 15 min/session cap. Developer $20/mo: 25 concurrent, 100 browser hours then $0.12/browser hr, 1GB proxies then $12/GB. Startup $99/mo: 100 concurrent, 500 hours then $0.10/hr, 5GB proxies then $10/GB. Scale custom: 250+ concurrent, usage-based.
Important: free plan has 1 browser hour and 15 min/session. Our example uses api_timeout 120 (2 min) — fits free plan.
Manageability assessment: yes, easy — pure API/SDK, no local infra, deterministic REST calls, observable via projects.usage. Main caveats: needs a paid API key I don't have; sessions cost money if leaked; live-run verification requires credentials.
Keep it concise.
Done. No blockers on the tooling side — one blocker on running it live.
What I built
/sandbox/repo — a two-file quickstart using the hosted product only (npm SDK + CDP client, no local Chromium, no Docker, nothing long-running):
| File | Purpose |
|---|---|
src/check-credentials.mjs | Pure REST smoke test — lists project, usage, recent sessions. Creates nothing, costs nothing. |
src/scrape-example.mjs | The quickstart: create session → puppeteer.connect(connectUrl) → navigate → title/<h1>/link count → screenshot → release. |
README.md, .env.example, package.json | Setup + run instructions. |
export BROWSERBASE_API_KEY=...
npm run check # free, safe
npm run scrape -- https://news.ycombinator.com
Verified: both scripts pass node --check; npm run check exits cleanly with a missing-key message; with a bogus key it reaches the real API and handles 401 Unauthorized gracefully. That's the full extent of what I can verify without real credentials.
Blocked: there's no BROWSERBASE_API_KEY in this environment, so I never executed a real session. I won't burn your money guessing at one — drop a key in and both scripts should run as written.
How pricing works
Pulled live from browserbase.com/pricing. Billing is per browser-minute while a session is alive (projects.usage() exposes exactly browserMinutes and proxyBytes — those are the two meters).
| Plan | Price | Concurrency | Browser hours | Proxy |
|---|---|---|---|---|
| Free | $0 | 3 | 1 hr, 15 min/session cap | — |
| Developer | $20/mo | 25 | 100 included, then $0.12/hr | 1 GB, then $12/GB |
| Startup | $99/mo | 100 | 500 included, then $0.10/hr | 5 GB, then $10/GB |
| Scale | Custom | 250+ | Usage-based | Usage-based |
Extras (Search/Fetch APIs, Agent runs, model tokens) are metered separately; the example touches none of them. Cost-control is the main thing to get right — a leaked session bills until it times out. Both scripts set api_timeout: 120 (fits inside the free plan's 15-min cap) and release in a finally block.
Will this be easy for me to manage?
Yes, unusually so. Everything is one-shot HTTPS calls to a hosted API — no daemons to babysit, no ports, no state files, no long-running processes. npm run check gives me a free, idempotent way to inspect state and spend at any time, and sessions are fully observable (status, sessions.debug() live-view URLs, recordings, logs). Failures surface as clean HTTP statuses I can branch on.
The two real caveats: (1) every mutation costs money, so I'll default to the read-only script and keep aggressive timeouts on anything that creates a session; (2) I can't self-verify end-to-end without a key in the environment, so the live path stays untested until you supply one.
AX Fundamentals
23 checks. Open an area for details.
This check is a quick preview. Test more tasks and models with Gauge Agents.
Test your product with Gauge Agents