Loading...
Loading...
Capture a full DevTools-protocol trace of any browser automation — CDP firehose, screenshots, and DOM dumps — then bisect the stream into per-page searchable buckets. Use when the user wants to debug a failed run, audit network/console/DOM activity, attach a trace to an in-progress session, or feed structured per-page summaries back into an agent loop so its next iteration learns from the last one.
npx skill4agent add browserbase/skills browser-tracebrowserbbbrowsernode --version # require Node 18+
which browse || npm install -g @browserbasehq/browse-cli@alpha
which bb || npm install -g @browserbasehq/cli # only needed for Browserbase remote
which jq || true # optional — used only for ad-hoc queryingbrowse cdpbrowse --help | grep -q "^\s*cdp " || echo "browse cdp not in this version — install @alpha"browse cdp <target>cdp/raw.ndjsonbrowse --ws <target> screenshotbrowse --ws <target> get html body--wsbisect-cdp.mjsraw.ndjsonPage.frameNavigated# 1. Launch Chrome with a debugger port (any user-data-dir keeps it isolated).
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--remote-debugging-port=9222 \
--user-data-dir=/tmp/chrome-o11y \
about:blank &
# 2. Start the tracer.
node scripts/start-capture.mjs 9222 my-run
# 3. Run your main automation against port 9222.
browse env local 9222
browse open https://example.com
# ...whatever the run does...
# 4. Stop and bisect.
node scripts/stop-capture.mjs my-run
node scripts/bisect-cdp.mjs my-runbb-capture.mjsbb-finalize.mjsBrowserbase ends a session as soon as its last CDP client disconnects. Always create withand attach an automation client before (or together with) the tracer.--keep-alivedoes this for you.bb-capture.mjs --new
export BROWSERBASE_API_KEY=...
# 1. Create a keep-alive session AND start the tracer in one step.
# Prints the session id, connectUrl prefix, and a live debugger URL you
# can open in a browser to watch the run interactively.
node scripts/bb-capture.mjs --new my-run
# 2. Drive automation. bb-capture stamped the session id into the manifest.
SID=$(jq -r .browserbase.session_id .o11y/my-run/manifest.json)
browse --connect "$SID" open https://example.com
browse --connect "$SID" open https://news.ycombinator.com
# 3. Stop the tracer, bisect, then pull platform artifacts and release.
node scripts/stop-capture.mjs my-run
node scripts/bisect-cdp.mjs my-run
node scripts/bb-finalize.mjs my-run --releasebb-capture.mjs--new# Pick a running session (filter client-side; bb sessions list has no --status flag)
bb sessions list | jq -r '.[] | select(.status == "RUNNING") | .id'
node scripts/bb-capture.mjs <session-id> mid-flight-debug
# ...tracer runs alongside the existing automation client; no disruption...
node scripts/stop-capture.mjs mid-flight-debug
node scripts/bisect-cdp.mjs mid-flight-debug
node scripts/bb-finalize.mjs mid-flight-debug # without --release: leave the session runningbb-capture.mjsbrowserbasemanifest.jsonbb-finalize.mjs<run>/browserbase/session.jsonbb sessions get<run>/browserbase/logs.jsonbb sessions logscdp/raw.ndjson<run>/browserbase/downloads.zipbb sessions recordingscreenshots/dom/debugger_url.o11y/<run-id>/
manifest.json run metadata: target, domains, started_at, stopped_at
index.jsonl one line per sample: {ts, screenshot, dom, url}
cdp/
raw.ndjson full CDP firehose (one JSON object per line)
summary.json {sessionId, duration, totalEvents, pages[]} — see shape below
network/{requests,responses,finished,failed,websocket}.jsonl session-wide buckets (always written)
console/{logs,exceptions}.jsonl
runtime/all.jsonl
log/entries.jsonl
page/{navigations,lifecycle,frames,dialogs,all}.jsonl
dom/all.jsonl (only if O11Y_DOMAINS includes DOM)
target/{attached,detached}.jsonl
pages/ per-page slices, indexed by top-level frameNavigated boundaries
000/ first concrete page
url.txt the URL for this page
summary.json this page's domains/network/timing block (same shape as a pages[] entry)
raw.jsonl firehose scoped to this page
network/, console/, page/, runtime/, log/, target/, dom/ same buckets, only non-empty files
screenshots/<iso-ts>.png one PNG per sample interval
dom/<iso-ts>.html one HTML dump per sample interval
browserbase/ added by bb-finalize.mjs (Browserbase runs only)
session.json final `bb sessions get` snapshot (proxyBytes, status, ended_at, …)
logs.json `bb sessions logs` output (often [])
downloads.zip `bb sessions downloads get` output (only if the session downloaded files)bb-capture.mjsmanifest.jsonbrowserbasesession_idproject_idregionstarted_atexpires_atkeep_alivedebugger_urlcdp/summary.jsonpages[]Page.frameNavigated{
"sessionId": "45f28023-…",
"duration": { "startMs": 1777312533000, "endMs": 1777312609000, "totalMs": 76000 },
"totalEvents": 420,
"pages": [
{
"pageId": 0,
"url": "https://example.com/",
"startMs": 1777312533000, "endMs": 1777312538886, "durationMs": 5886,
"eventCount": 60,
"domains": {
"Network": { "count": 18, "errors": 1 },
"Console": { "count": 2 },
"Page": { "count": 24 },
"Runtime": { "count": 13 }
},
"network": { "requests": 4, "failed": 1, "byType": { "Document": 2, "Script": 1, "Other": 1 } }
}
]
}startMsendMsdurationMsmanifest.started_atdomains[*]errorswarningsquery.mjsscripts/query.mjs <run-id> <command>node scripts/query.mjs my-run list # one-line table of pages
node scripts/query.mjs my-run page 1 # full summary for page 1
node scripts/query.mjs my-run page 1 network/failed # cat failed.jsonl for page 1
node scripts/query.mjs my-run errors # all errors across pages, attributed by pid
node scripts/query.mjs my-run errors 2 # errors from page 2 only
node scripts/query.mjs my-run hosts # top hosts by request count
node scripts/query.mjs my-run host api.example.com # all requests/responses for a host
node scripts/query.mjs my-run summary # full summary.jsoncdp/summary.jsoncdp/pages/<pid>/jqrg# All failed network requests (use jq -c to keep it line-delimited)
jq -c '.params' .o11y/<run>/cdp/network/failed.jsonl
# Find requests to a specific host
jq -c 'select(.params.request.url | test("api\\.example\\.com"))' \
.o11y/<run>/cdp/network/requests.jsonl
# 4xx/5xx responses
jq -c 'select(.params.response.status >= 400)
| {status: .params.response.status, url: .params.response.url}' \
.o11y/<run>/cdp/network/responses.jsonl
# Console errors only
jq -c 'select(.params.type == "error")' .o11y/<run>/cdp/console/logs.jsonl
# Sequence of URLs visited
jq -r '.params.frame.url' .o11y/<run>/cdp/page/navigations.jsonl
# Find the screenshot taken closest to a timestamp (e.g., when an exception fired)
ls .o11y/<run>/screenshots/ | sort | awk -v t=20260427T1714123NZ '
$0 >= t { print; exit }'bb-capture.mjs--keep-alive--releasebb-finalize.mjs --release--newbb-capture.mjs <session-id>bb-finalize.mjs--release--keep-aliveNetwork Console Runtime Log PageDOMO11Y_DOMAINS="$O11Y_DOMAINS DOM"--connect <session-id>browse env remotestop-capture.mjsstopped_atbisect-cdp.mjsraw.ndjsonbrowse cdp exited immediatelybb sessions get <id>statusCOMPLETED--keep-aliveraw.ndjsonindex.jsonlurl--timeoutBB_SESSION_TIMEOUT=1800 node scripts/bb-capture.mjs --new ...bb-capture.mjs <id>bb sessions list | jq '.[] | select(.status == "RUNNING")'browserbase/logs.json[]bb sessions logscdp/raw.ndjsonbb sessions recordingscreenshots/dom/