捕获任何浏览器自动化的完整 DevTools 协议跟踪——CDP 数据流、截图和 DOM 转储——然后将流分割成按页面可搜索的桶。当用户想要调试失败的运行、审计网络/控制台/DOM 活动、将跟踪附加到正在进行的会话,或向代理循环反馈结构化的每页摘要以便下一次迭代从上次学习时使用。
Browser Trace
向已由主自动化驱动的浏览器会话附加一个第二个只读 CDP 客户端。跟踪将完整的 DevTools 数据流记录到 NDJSON,并行轮询截图和 DOM 转储,并将所有内容切片成 bash 工具可搜索的目录树。
此技能不驱动页面——它只监听。将其与 browser 技能、browse、Stagehand、Playwright 或任何其他支持 CDP 的工具配对。
何时使用
- 用户想要调试浏览器自动化运行(表单失败、元素缺失、导航挂起、JS 异常)。
- 用户有一个正在运行的自动化,并希望在不重启的情况下中途附加跟踪。
- 用户想要将 CDP 数据流分割成网络/控制台/DOM/页面桶。
- 用户希望随时间获取截图和 DOM 快照,并通过时间戳与 CDP 事件关联。
如果用户只想驱动浏览器,请改用 browser 技能。
设置检查
node --version # 需要 Node 18+
which browse || npm install -g browse
which jq || true # 可选——仅用于临时查询
验证 browse cdp 存在:
browse --help | grep -q "^\s*cdp " || echo "browse cdp 不可用——请更新 browse"
工作原理
每个 Chrome DevTools 目标都接受多个并发 CDP 客户端。您的主自动化是一个客户端;此技能添加第二个客户端,仅启用观察域(Network、Console、Runtime、Log、Page),从不发送操作命令。
跟踪器由三部分组成:
- 数据流:
browse cdp <target>将每个 CDP 事件作为一行一个 JSON 对象流式传输到cdp/raw.ndjson。 - 采样器:一个轮询循环按间隔(默认 2 秒)调用
browse screenshot --cdp <target> --path <file>和browse get html body --cdp <target>。辅助程序在采样时传递--cdp,以便从其自身进程附加到跟踪目标;一旦 browse 守护进程会话附加到 CDP 目标,该会话中的后续命令无需重复--cdp。 - 分割器:运行后,
bisect-cdp.mjs遍历raw.ndjson一次,将其按 CDP 方法分割成每个桶的 JSONL 文件,并额外使用顶级Page.frameNavigated事件作为边界按页面分割。
快速开始
本地 Chrome
# 1. 启动带有调试端口的 Chrome(任何用户数据目录可保持隔离)。
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--remote-debugging-port=9222 \
--user-data-dir=/tmp/chrome-o11y \
about:blank &
# 2. 启动跟踪器。
node scripts/start-capture.mjs 9222 my-run
# 3. 针对端口 9222 运行您的主自动化。
browse open https://example.com --cdp 9222
# ...运行所做的任何操作...
# 4. 停止并分割。
node scripts/stop-capture.mjs my-run
node scripts/bisect-cdp.mjs my-run
Browserbase 远程
两个辅助程序封装了平台端的簿记:bb-capture.mjs 创建或附加到会话并启动跟踪器;bb-finalize.mjs 在运行结束时将平台工件(最终会话元数据、服务器日志、下载)拉入运行目录。
Browserbase 在其最后一个 CDP 客户端断开连接时结束会话。使用
--keep-alive创建,然后在跟踪器之前或同时将自动化附加到会话的connectUrl。bb-capture.mjs --new处理保持活动会话和跟踪器设置;您的自动化仍需要附加。
export BROWSERBASE_API_KEY=...
# 1. 一步创建保持活动会话并启动跟踪器。
# 打印会话 ID、connectUrl 前缀和实时调试器 URL,您可以在浏览器中打开以交互式观看运行。
node scripts/bb-capture.mjs --new my-run
# 2. 驱动自动化。bb-capture 将会话 ID 写入清单。
SID=$(jq -r .browserbase.session_id .o11y/my-run/manifest.json)
CONNECT_URL="$(browse cloud sessions get "$SID" | jq -r .connectUrl)"
BROWSE_NAME=my-run-browser
browse open https://example.com --cdp "$CONNECT_URL" --session "$BROWSE_NAME"
browse open https://news.ycombinator.com --session "$BROWSE_NAME"
# 3. 停止跟踪器、分割,然后拉取平台工件并释放。
node scripts/stop-capture.mjs my-run
node scripts/bisect-cdp.mjs my-run
node scripts/bb-finalize.mjs my-run --release
附加到已经运行的会话(例如您的生产工作进程创建的会话)——bb-capture.mjs 接受会话 ID 而不是 --new:
# 选择一个正在运行的会话(客户端过滤;browse cloud sessions list 没有 --status 标志)
browse cloud sessions list | jq -r '.[] | select(.status == "RUNNING") | .id'
node scripts/bb-capture.mjs <session-id> mid-flight-debug
# ...跟踪器与现有自动化客户端并行运行;无中断...
node scripts/stop-capture.mjs mid-flight-debug
node scripts/bisect-cdp.mjs mid-flight-debug
node scripts/bb-finalize.mjs mid-flight-debug # 不带 --release:保持会话运行
从 Browserbase 平台获得的内容
bb-capture.mjs 向 manifest.json 添加一个 browserbase 块(会话 ID、项目、区域、started_at、expires_at、调试器 URL)。bb-finalize.mjs 写入:
<run>/browserbase/session.json— 最终的browse cloud sessions get快照(proxyBytes、status、ended_at、viewport 等)<run>/browserbase/logs.json—browse cloud sessions logs输出。通常为空。cdp/raw.ndjson中的 CDP 数据流是事实来源;这是辅助通道。<run>/browserbase/downloads.zip— 会话下载的文件(如果有)(脚本会丢弃没有文件时得到的 22 字节空 zip)
会话回放工件获取已弃用,不再获取。使用 screenshots/ 中的截图和 dom/ 中的 DOM 转储作为视觉真实依据。
清单中的实时 debugger_url 打开一个由 Browserbase 提供的交互式 Chrome DevTools 视图——方便在跟踪器将数据流捕获到磁盘时观看长时间运行的自动化。
文件系统布局
.o11y/<run-id>/
manifest.json 运行元数据:目标、域、started_at、stopped_at
index.jsonl 每个样本一行:{ts, screenshot, dom, url}
cdp/
raw.ndjson 完整 CDP 数据流(每行一个 JSON 对象)
summary.json {sessionId, duration, totalEvents, pages[]} — 见下方形状
network/{requests,responses,finished,failed,websocket}.jsonl 会话级桶(始终写入)
console/{logs,exceptions}.jsonl
runtime/all.jsonl
log/entries.jsonl
page/{navigations,lifecycle,frames,dialogs,all}.jsonl
dom/all.jsonl (仅当 O11Y_DOMAINS 包含 DOM 时)
target/{attached,detached}.jsonl
pages/ 按页面切片,以顶级 frameNavigated 边界索引
000/ 第一个具体页面
url.txt 此页面的 URL
summary.json 此页面的域/网络/时间块(与 pages[] 条目形状相同)
raw.jsonl 限定于此页面的数据流
network/, console/, page/, runtime/, log/, target/, dom/ 相同桶,仅非空文件
screenshots/<iso-ts>.png 每个采样间隔一个 PNG
dom/<iso-ts>.html 每个采样间隔一个 HTML 转储
browserbase/ 由 bb-finalize.mjs 添加(仅 Browserbase 运行)
session.json 最终的 `browse cloud sessions get` 快照(proxyBytes、status、ended_at 等)
logs.json `browse cloud sessions logs` 输出(通常为 [])
downloads.zip `browse cloud sessions downloads get` 输出(仅当会话下载了文件时)
当通过 bb-capture.mjs 启动运行时,manifest.json 还带有一个顶级 browserbase 块:session_id、project_id、region、started_at、expires_at、keep_alive、debugger_url。
摘要形状
cdp/summary.json 是任何分析的入口点:它包含会话级总计和一个由顶级 Page.frameNavigated 索引的 pages[] 数组。每个页面条目按导航顺序发出(页面 0 = 第一个具体 URL)。
{
"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 是挂钟毫秒,源自 manifest.started_at 加上每个事件 CDP 单调时间戳的偏移。domains[*] 仅在非零时包含 errors/warnings 键。
使用 query.mjs 深入探索
对于交互式探索,使用 scripts/query.mjs <run-id> <command> 而不是记住路径:
node scripts/query.mjs my-run list # 页面的一行表格
node scripts/query.mjs my-run page 1 # 页面 1 的完整摘要
node scripts/query.mjs my-run page 1 network/failed # 显示页面 1 的 failed.jsonl
node scripts/query.mjs my-run errors # 所有页面中的错误,按 pid 归属
node scripts/query.mjs my-run errors 2 # 仅页面 2 的错误
node scripts/query.mjs my-run hosts # 按请求数排序的顶级主机
node scripts/query.mjs my-run host api.example.com # 特定主机的所有请求/响应
node scripts/query.mjs my-run summary # 完整 summary.json
幕后它只读取 cdp/summary.json 和 cdp/pages/<pid>/ 树——一旦您了解形状,可以随意使用原始 jq/rg 绕过它。
顶级遍历配方
# 所有失败的网络请求(使用 jq -c 保持行分隔)
jq -c '.params' .o11y/<run>/cdp/network/failed.jsonl
# 查找特定主机的请求
jq -c 'select(.params.request.url | test("api\\.example\\.com"))' \
.o11y/<run>/cdp/network/requests.jsonl
# 4xx/5xx 响应
jq -c 'select(.params.response.status >= 400)
| {status: .params.response.status, url: .params.response.url}' \
.o11y/<run>/cdp/network/responses.jsonl
# 仅控制台错误
jq -c 'select(.params.type == "error")' .o11y/<run>/cdp/console/logs.jsonl
# 访问的 URL 序列
jq -r '.params.frame.url' .o11y/<run>/cdp/page/navigations.jsonl
# 查找最接近时间戳的截图(例如,异常触发时)
ls .o11y/<run>/screenshots/ | sort | awk -v t=20260427T1714123NZ '
$0 >= t { print; exit }'
请参阅 REFERENCE.md 获取完整的 jq 配方库和按方法分割的映射。请参阅 EXAMPLES.md 获取端到端调试场景。
最佳实践
- 在 Browserbase 上使用
bb-capture.mjs:它强制--keep-alive、获取 connectUrl、捕获调试器 URL 并写入清单。手动操作容易出错。 - 不要
--release不属于您的会话:bb-finalize.mjs --release适用于您使用--new创建的会话。当通过bb-capture.mjs <session-id>附加到生产会话时,运行bb-finalize.mjs而不带--release,以便原始自动化继续运行。 - 远程时顺序很重要:在 Browserbase 上,在跟踪器之前(或同时)附加主自动化客户端,并使用
--keep-alive创建会话。否则,会话会在跟踪器的 WS 关闭时立即结束。 - 轮询频率不要快于约 1 秒:每次采样都会运行浏览器 CLI 读取命令并截图 Chrome。2 秒是良好的默认值。
- 有选择地选择域:默认值(
Network Console Runtime Log Page)覆盖大多数调试。通过O11Y_DOMAINS="$O11Y_DOMAINS DOM"添加DOM以获取 DOM 树突变(非常嘈杂)。 - 在远程上为自动化客户端重用同一个 Browserbase 会话,通过使用
browse open ... --cdp "$CONNECT_URL" --session <name>附加到该会话的connectUrl。--session标志命名本地 browse 守护进程;它不是 Browserbase 会话附加标志。 - 始终运行
stop-capture.mjs,即使在崩溃后,这样后台进程不会残留,并且清单会获得stopped_at。 - 每次运行只分割一次:
bisect-cdp.mjs是幂等的——它每次从raw.ndjson覆盖每个桶的文件。
故障排除
browse cdp exited immediately:通常意味着目标不可达(端口错误)或 Browserbase 会话已结束。对于远程,使用browse cloud sessions get <id>验证——如果status是COMPLETED,使用--keep-alive重新创建并先附加自动化。- 即使进程在运行,
raw.ndjson为空:确认有 CDP 客户端实际在驱动页面。跟踪器只发出浏览器生成的事件,因此空闲浏览器会产生约 5 行附加/发现消息,然后没有其他内容。 - 所有截图看起来相同:检查
index.jsonl——如果url没有变化,页面尚未导航。轮询循环独立于主自动化的节奏运行。 - Browserbase 会话在运行中结束:可能达到了
--timeout。使用更高的超时重新创建(BB_SESSION_TIMEOUT=1800 node scripts/bb-capture.mjs --new ...)或移除超时标志。 bb-capture.mjs <id>显示 "not RUNNING":您尝试附加的会话已结束。使用browse cloud sessions list | jq '.[] | select(.status == "RUNNING")'列出候选会话并重试。browserbase/logs.json为空[]:预期行为——browse cloud sessions logs在实践中很稀疏。cdp/raw.ndjson中的 CDP 数据流是事实来源。- 会话录制(rrweb)在哪里?:会话回放工件获取已弃用;此技能不获取它。使用
screenshots/中的截图流和dom/中的 DOM 转储。
完整参考,请参见 REFERENCE.md。
示例调试运行,请参见 EXAMPLES.md。






