Labsco
browserbase logo

browser-trace

✓ Official3,600

by browserbase · part of browserbase/skills

Capture a full DevTools-protocol trace of any browser automation — CDP firehose, screenshots, and DOM dumps — then bisect the stream into per-page searchable…

🔥🔥🔥✓ VerifiedFreeQuick setup
🧩 One of 7 skills in the browserbase/skills package — works on its own, and pairs well with its siblings.

Capture a full DevTools-protocol trace of any browser automation — CDP firehose, screenshots, and DOM dumps — then bisect the stream into per-page searchable…

Inspect the full instructions your agent will receiveExpand

This is the exact playbook injected into your agent when the skill activates — shown here so you can audit it before installing. You don't need to read it to use the skill.

by browserbase

Capture a full DevTools-protocol trace of any browser automation — CDP firehose, screenshots, and DOM dumps — then bisect the stream into per-page searchable… npx skills add https://github.com/browserbase/skills --skill browser-trace Download ZIPGitHub3.6k

Browser Trace

Attach a second, read-only CDP client to a browser session that is already being driven by your main automation. The trace records the full DevTools firehose to NDJSON, polls for screenshots and DOM dumps in parallel, and slices everything into a directory tree that bash tools can search.

This skill does not drive pages — it only listens. Pair it with the browser skill, browse, Stagehand, Playwright, or anything else that speaks CDP.

When to use

  • The user wants to debug a browser-automation run (failing form, missing element, hung navigation, JS exception).

  • The user has a running automation and wants to attach a trace mid-flight without restarting it.

  • The user wants to split a CDP firehose into network / console / DOM / page buckets.

  • The user wants screenshots + DOM snapshots over time, joined to CDP events by timestamp.

If the user just wants to drive the browser, use the browser skill instead.

How it works

Every Chrome DevTools target accepts multiple concurrent CDP clients. Your main automation is one client; this skill adds a second one that only enables observation domains (Network, Console, Runtime, Log, Page) and never sends action commands.

The tracer has three pieces:

  • Firehose: browse cdp <target> streams every CDP event as one JSON object per line to cdp/raw.ndjson.

  • Sampler: a polling loop calls browse screenshot --cdp <target> --path <file> and browse get html body --cdp <target> on an interval (default 2s). The helper passes --cdp when it samples so it can attach to the traced target from its own process; once a browse daemon session is attached to a CDP target, follow-up commands in that session do not need to repeat --cdp.

  • Bisector: after the run, bisect-cdp.mjs walks raw.ndjson once, slices it into per-bucket JSONL files keyed by CDP method, and additionally bisects per page using top-level Page.frameNavigated events as boundaries.

Filesystem layout

Copy & paste — that's it
.o11y/ /
 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/ .png one PNG per sample interval
 dom/ .html one HTML dump per sample interval
 browserbase/ added by bb-finalize.mjs (Browserbase runs only)
 session.json final `browse cloud sessions get` snapshot (proxyBytes, status, ended_at, …)
 logs.json `browse cloud sessions logs` output (often [])
 downloads.zip `browse cloud sessions downloads get` output (only if the session downloaded files)

When a run was started via bb-capture.mjs, manifest.json also carries a top-level browserbase block: session_id, project_id, region, started_at, expires_at, keep_alive, debugger_url.

Summary shape

cdp/summary.json is the entry point for any analysis: it has session-level totals and a pages[] array indexed by top-level Page.frameNavigated. Per-page entries are emitted in navigation order (page 0 = first concrete URL).

Copy & paste — that's it
{
 "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 } }
 }
 ]
}

startMs / endMs / durationMs are wall-clock ms, derived from manifest.started_at plus the offset of each event's CDP monotonic timestamp. domains[*] only includes errors/warnings keys when non-zero.

Drilling in with query.mjs

For interactive exploration, use scripts/query.mjs <run-id> <command> instead of remembering paths:

Copy & paste — that's it
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.json

Behind the scenes it just reads cdp/summary.json and the cdp/pages/<pid>/ tree — feel free to bypass it with raw jq/rg once you know the shape.

Top traversal recipes

Copy & paste — that's it
# All failed network requests (use jq -c to keep it line-delimited)
jq -c '.params' .o11y/ /cdp/network/failed.jsonl

# Find requests to a specific host
jq -c 'select(.params.request.url | test("api\\.example\\.com"))' \
 .o11y/ /cdp/network/requests.jsonl

# 4xx/5xx responses
jq -c 'select(.params.response.status >= 400)
 | {status: .params.response.status, url: .params.response.url}' \
 .o11y/ /cdp/network/responses.jsonl

# Console errors only
jq -c 'select(.params.type == "error")' .o11y/ /cdp/console/logs.jsonl

# Sequence of URLs visited
jq -r '.params.frame.url' .o11y/ /cdp/page/navigations.jsonl

# Find the screenshot taken closest to a timestamp (e.g., when an exception fired)
ls .o11y/ /screenshots/ | sort | awk -v t=20260427T1714123NZ '
 $0 >= t { print; exit }'

See REFERENCE.md for the full jq recipe library and a method-by-method bisect map. See EXAMPLES.md for end-to-end debug scenarios.

Best practices

  • Use bb-capture.mjs on Browserbase: it enforces --keep-alive, fetches the connectUrl, captures the debugger URL, and stamps the manifest. Doing it manually invites mistakes.

  • Don't --release a session you don't own: bb-finalize.mjs --release is for sessions you created with --new. When attaching to a production session via bb-capture.mjs <session-id>, run bb-finalize.mjs without --release so the original automation keeps running.

  • Order matters for remote: on Browserbase, attach the main automation client before (or together with) the tracer, and create the session with --keep-alive. Otherwise the session ends as soon as the tracer's WS closes.

  • Don't poll faster than ~1s: each sample runs browser CLI read commands and screenshots Chrome. 2s is a good default.

  • Pick domains deliberately: defaults (Network Console Runtime Log Page) cover most debugging. Add DOM for DOM-tree mutations (very noisy) via O11Y_DOMAINS="$O11Y_DOMAINS DOM".

  • Reuse one Browserbase session for the automation client on remote by attaching to that session's connectUrl with browse open ... --cdp "$CONNECT_URL" --session <name>. The --session flag names the local browse daemon; it is not a Browserbase session attach flag.

  • Always run stop-capture.mjs, even after a crash, so background processes don't linger and the manifest gets stopped_at.

  • Bisect once per run: bisect-cdp.mjs is idempotent — it overwrites the per-bucket files from raw.ndjson each time.