How ego-browser Integrates with the Chrome DevTools Protocol (CDP) for Browser Control

The ego-browser package bridges high-level automation helpers to Chrome DevTools Protocol commands through a private ego runtime that handles session management, message transport, and automatic reconnection in the closed-source ego lite application.

The ego-browser integration with CDP (Chrome DevTools Protocol) enables scriptable browser automation for AI agents by wrapping low-level protocol commands in ergonomic JavaScript helpers. This article examines how the citrolabs/ego-lite repository orchestrates CDP communication, from raw message transport to polished driver-level APIs.


CDP Transport Layer: The Core Messaging Infrastructure

All CDP communication in ego-browser funnels through src/browser-runtime.ts. This file encapsulates the complete transport stack and session lifecycle.

The runtime exposes a native bridge via ego.sendCDPMessage, which accepts a JSON-encoded CDP request and returns the parsed response. According to the source code, this function is the sole entry point between the JavaScript harness and the closed-source ego native runtime.

Session management happens automatically:

  • Attachment: The runtime attaches to the browser's CDP session on first use
  • Reconnection: If the session detaches (e.g., after a page crash), the runtime re-attaches transparently
  • Caching: Session handles are cached for approximately 2 seconds to eliminate redundant handshake overhead

An internal event queue in browser-runtime.ts buffers up to 10,000 CDP events. This queue powers observability helpers like observe(), ensuring no events are dropped during asynchronous operations such as screenshots or DOM snapshots.


Evaluating CDP Commands: The cdp() and js() Helpers

The src/cdp-eval.ts file provides two foundational wrappers for CDP execution:

cdp(): Direct CDP Method Invocation

// Enable network monitoring via CDP
await cdp('Network.enable')

The cdp() function accepts a CDP method name (e.g., "Network.enable", "Page.navigate") and an optional parameters object. It forwards the request to browserRuntime.sendCDPMessage and returns the raw CDP response payload.

js(): JavaScript Evaluation in Page Context

// Extract the page title
const title = await js('document.title')
console.log('Page title:', title)

The js() helper builds on cdp() by invoking the Runtime.evaluate CDP method. It automatically wraps expressions in an IIFE with an explicit return statement, allowing direct evaluation of top-level expressions without manual wrapping.


Driver Layer: High-Level Actions as CDP Sequences

The src/driver/ directory translates common automation patterns into precise CDP command sequences. Each driver module abstracts payload construction while preserving full CDP fidelity.

await nav('https://example.com')
// Internally calls: cdp('Page.navigate', { url: 'https://example.com' })

Mouse Interactions (src/driver/pointer.ts)

await click('css:#login-button')
// Maps to: Input.dispatchMouseEvent with calculated coordinates

The pointer driver resolves element locators, computes viewport coordinates, and dispatches Input.dispatchMouseEvent with appropriate type values (mousePressed, mouseReleased).

Keyboard Input (src/driver/keyboard.ts)

await type('css:#username', 'alice')
// Dispatches: Input.dispatchKeyEvent for each character

Screenshots (src/driver/screencast.ts)

await screenshot({ path: 'login.png' })
// Calls: Page.captureScreenshot with format and quality parameters

Session and Event Management for Robust Automation

The browser-runtime.ts event queue serves critical reliability functions:

  • Screenshot synchronization: observe() can capture DOM state without losing intervening CDP events
  • Network tracking: Buffered Network.* events remain available for post-navigation analysis
  • Race condition prevention: Queued events ensure deterministic behavior during rapid command sequences

The 10,000-entry limit provides headroom for long-running automation scripts while preventing unbounded memory growth.


Error Handling and Transient Retry Logic

When CDP calls fail due to recoverable conditions—typically session detachment during navigation—the runtime throws ElementResolutionError with a transient: true flag. This signal enables automatic retry in higher-level wait loops.

// waitFor in src/driver/waits.ts leverages transient detection
await waitFor('css:.ready', { timeout: 5 })
// Retries CDP element queries until found or timeout exceeded

The src/driver/waits.ts module implements exponential backoff for transient failures, distinguishing them from permanent resolution failures (invalid selectors, deleted elements).


Summary

  • Transport: src/browser-runtime.ts manages CDP sessions via ego.sendCDPMessage with automatic reconnection and 2-second session caching
  • Primitives: src/cdp-eval.ts exposes cdp() for raw CDP calls and js() for evaluated expressions
  • Drivers: src/driver/ modules map high-level actions (nav, click, type, screenshot) to specific CDP methods
  • Reliability: Event queue (10K entries) and transient error classification enable robust asynchronous automation

Frequently Asked Questions

What CDP methods does ego-browser support?

ego-browser supports the full CDP surface through the cdp() helper. Higher-level drivers in src/driver/ use common methods including Page.navigate, Input.dispatchMouseEvent, Input.dispatchKeyEvent, Page.captureScreenshot, and Runtime.evaluate. You can invoke any CDP domain directly via cdp('Domain.method', params).

How does ego-browser handle browser crashes or disconnections?

The browser-runtime.ts module detects session detachment and automatically re-attaches to the browser's CDP endpoint. Failed calls during reconnection are marked as transient errors, allowing wait loops and retries to resume seamlessly once the session restores.

Can I use ego-browser without the closed-source ego runtime?

No. The CDP integration depends on ego.sendCDPMessage, a native function provided exclusively by the ego lite application. The ego-browser package is designed as a harness for this runtime, not a standalone CDP client.

How does the JavaScript evaluation wrapper work?

The js() function in src/cdp-eval.ts takes a JavaScript expression, wraps it in an IIFE with return, and executes it via Runtime.evaluate. This pattern ensures top-level expressions yield values without requiring explicit return statements from the caller.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →