Skip to content
Gauge

ax-check.com

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.

Onboarding

Give agents a clear login handoff and a way to resume setup.

Agents cannot progress through onboarding without human help. Provide an agent-accessible path through authentication and setup.

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.

piv0.84.2
modelQwen 3.8 Maxcwd/sandbox/repo
Help me build a simple example using Browserbase. Tell me how pricing works, and briefly tell me whether this product will be easy for you to manage. Let me know if you get blocked. If this product has no developer workflow you can act on, say so plainly and stop. Stay light: use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop.
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
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
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
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"
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
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",
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 ===
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.
     */
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);
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
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

Completed
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"
}
}
Thinking…

Now write src/check-credentials.mjs and src/scrape-example.mjs.

File edits

1 file

Completed
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 check
import { 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);
}
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';
}
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

Completed
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 check
import { 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);
}
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

Completed
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.com
import { 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 crash
browserSettings: { 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.`);
}
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;
}
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
Thinking…

Now .env.example and README, then run the check to show blocked state.

File edits

1 file

Completed
Written.env.exampleView changes

/sandbox/repo/.env.example

Written content · previous contents were not recorded

# Required. https://www.browserbase.com/settings
BROWSERBASE_API_KEY=
# Optional — inferred from the API key if omitted.
BROWSERBASE_PROJECT_ID=
Thinking…

Now README, then run the check script to show the blocked state.

File edits

1 file

Completed
WrittenREADME.mdView changes

/sandbox/repo/README.md

Written content · previous contents were not recorded

# Browserbase hello world
Minimal hosted-browser example using the official Node SDK (`@browserbasehq/sdk`)
plus `puppeteer-core` as a CDP client. **No local Chromium, no Docker, no local
service stack** — the browser runs on Browserbase's infrastructure and you
connect to it over a WebSocket.
## Setup
```bash
npm install
export BROWSERBASE_API_KEY=... # https://www.browserbase.com/settings
# optional: export BROWSERBASE_PROJECT_ID=...
```
## Run
```bash
npm run check # REST-only smoke test; creates nothing, costs nothing
npm run scrape # scrape https://example.com
npm run scrape -- https://news.ycombinator.com
```
`scrape` creates a session, prints the live debugger URL, reads the page
title / `<h1>` / link count, writes `out/screenshot.png`, then releases the
session.
## 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-destructs
after 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 watch
the 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.
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
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
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
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('---')
EOF
200 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
---
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):

FilePurpose
src/check-credentials.mjsPure REST smoke test — lists project, usage, recent sessions. Creates nothing, costs nothing.
src/scrape-example.mjsThe quickstart: create session → puppeteer.connect(connectUrl) → navigate → title/<h1>/link count → screenshot → release.
README.md, .env.example, package.jsonSetup + 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).

PlanPriceConcurrencyBrowser hoursProxy
Free$031 hr, 15 min/session cap—
Developer$20/mo25100 included, then $0.12/hr1 GB, then $12/GB
Startup$99/mo100500 included, then $0.10/hr5 GB, then $10/GB
ScaleCustom250+Usage-basedUsage-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

AX Check by Gauge