Skip to content

Commit e87f167

Browse files
derekmeeganclaude
andauthored
feat(cli): emit Page.lifecycleEvent in browse cdp (browserbase#2056)
## Summary `browse cdp` enables the Page domain via `Page.enable`, but `Page.enable` does not by itself emit `Page.lifecycleEvent` — that requires a separate `Page.setLifecycleEventsEnabled` opt-in. As a result, consumers of `browse cdp` today see only `Page.frameNavigated` and miss the granular lifecycle milestones (`init`, `commit`, `DOMContentLoaded`, `load`, `firstPaint`, `firstContentfulPaint`, `firstMeaningfulPaint`, `networkAlmostIdle`, `networkIdle`). This PR enables lifecycle events whenever the Page domain is enabled (so it covers both the default-domain set and explicit `--domain Page`), and adds a `--pretty` formatter case that prints the milestone name. ## Why These events are exactly what observability/perf tools want from the firehose: - approximate page-ready timing (`DOMContentLoaded` / `load`) - network-settled signal (`networkIdle`) - paint timing (`firstPaint` / `firstContentfulPaint` / `firstMeaningfulPaint`) Without the opt-in, all of those have to be approximated from `Page.frameNavigated` + `Network.loadingFinished`, which loses the per-milestone resolution. ## Verification Built locally with `pnpm exec tsx src/index.ts cdp 9333` against a debuggable Chrome and triggered an `example.com` navigation. Before this patch, no `Page.lifecycleEvent` lines. After: ``` [Page.lifecycleEvent] init [Page.lifecycleEvent] commit [Page.lifecycleEvent] DOMContentLoaded [Page.lifecycleEvent] firstPaint [Page.lifecycleEvent] firstContentfulPaint [Page.lifecycleEvent] firstMeaningfulPaint [Page.lifecycleEvent] load [Page.lifecycleEvent] networkAlmostIdle [Page.lifecycleEvent] networkIdle ``` Default mode (NDJSON) emits the same events with full params: ```json {"sessionId":"…","method":"Page.lifecycleEvent","params":{"frameId":"…","loaderId":"…","name":"DOMContentLoaded","timestamp":468107.080156}} ``` ## Test plan - [ ] `pnpm --filter @browserbasehq/browse-cli typecheck` passes - [ ] `pnpm --filter @browserbasehq/browse-cli eslint` passes - [ ] `pnpm --filter @browserbasehq/browse-cli test` — no new failures (pre-existing failures in `cli.test.ts` / `mode.test.ts` reproduce on `main` and are unrelated to this change) - [ ] Manual: `browse cdp <port>` against a debuggable Chrome shows `Page.lifecycleEvent` lines after a navigation - [ ] Manual: `browse cdp <port> --pretty` formats `[Page.lifecycleEvent] <name>` - [ ] Manual: `browse cdp <port> --domain Network --domain Console` (no Page) emits no lifecycle events — the opt-in is gated correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ed4db53 commit e87f167

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

.changeset/cdp-lifecycle-events.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@browserbasehq/browse-cli": patch
3+
---
4+
5+
`browse cdp` now also calls `Page.setLifecycleEventsEnabled` whenever the Page domain is enabled, so consumers receive `Page.lifecycleEvent` notifications (`init`, `commit`, `DOMContentLoaded`, `load`, `firstPaint`, `firstContentfulPaint`, `networkAlmostIdle`, `networkIdle`, etc.) in addition to `Page.frameNavigated`. `--pretty` mode formats lifecycle events with the milestone name. No effect on consumers that pass `--domain` without `Page`.

packages/cli/src/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,6 +2754,18 @@ program
27542754
} else {
27552755
sendCDP(ws, `${domain}.enable`, {}, sessionId);
27562756
}
2757+
2758+
// Page.enable does not emit Page.lifecycleEvent on its own; it requires
2759+
// a separate opt-in. Enable it so consumers see DOMContentLoaded, load,
2760+
// firstPaint, networkIdle, etc.
2761+
if (domain === "Page") {
2762+
sendCDP(
2763+
ws,
2764+
"Page.setLifecycleEventsEnabled",
2765+
{ enabled: true },
2766+
sessionId,
2767+
);
2768+
}
27572769
}
27582770
}
27592771

@@ -2822,6 +2834,11 @@ program
28222834
if (url) line += ` ${url}`;
28232835
break;
28242836
}
2837+
case "Page.lifecycleEvent": {
2838+
const name = (params?.name as string) ?? "";
2839+
if (name) line += ` ${name}`;
2840+
break;
2841+
}
28252842
case "Target.attachedToTarget": {
28262843
const info = params?.targetInfo as
28272844
| { type?: string; url?: string }

0 commit comments

Comments
 (0)