How ego-browser Drives Browser Automation for AI Agents: A Deep Dive into the CDP Architecture
ego-browser is a lightweight Node.js harness that exposes high-level automation helpers (click, goto, waitForSelector) which internally translate actions into Chrome DevTools Protocol (CDP) messages sent to the embedded ego runtime.
This browser automation layer, developed in the citrolabs/ego-lite repository, gives AI agents a Playwright-like API without the overhead of heavy frameworks. The architecture prioritizes low-level CDP efficiency, session resilience, and task-space isolation—critical requirements for autonomous agents operating at scale.
The Three-Layer Architecture of ego-browser Automation
ego-browser organizes its automation capabilities into distinct architectural layers. Each layer abstracts complexity while maintaining direct access to the underlying Chrome DevTools Protocol.
CDP Transport Layer: Session Management and Message Routing
The foundation sits in src/browser-runtime.ts. This module maintains a single page session, buffers incoming CDP events, and handles automatic re-attachment when sessions drop.
Key responsibilities include:
Target.attachToTarget— establishes the initial connection to the active tabPage.enable,DOM.enable— enables domain-specific events for the sessionensureSession()— lazily bootstraps connections on first helper invocationbrowserCdp()— injects the current session ID when callers omit it
Session loss is transparently handled. The runtime detects disconnections and re-attaches without throwing errors to the consuming AI agent.
Helper Façade: The Public API Surface
src/helpers.ts re-exports all automation primitives and implements task-space management. This is the layer most AI agents interact with directly.
Core functions exported include:
- Navigation:
goto(url),reload(),goBack() - Interaction:
click(selector),fill(selector, value),hover(selector) - Observation:
waitForSelector(selector),screenshot(options),evaluate(fn) - Task isolation:
newTaskSpace(),useOrCreateTaskSpace()
The façade also normalizes errors. CDP-level exceptions get transformed into descriptive messages that agents can parse programmatically.
Driver Modules: Concrete Action Implementation
Five specialized drivers in src/driver/ compose raw CDP commands into coherent actions:
| Driver | File | Capabilities |
|---|---|---|
| Pointer | driver/pointer.ts |
click, drag, scroll, mouse event dispatch via Input.dispatchMouseEvent |
| Keyboard | driver/keyboard.ts |
type, pressKey, form submission, Input.dispatchKeyEvent |
| Navigation | driver/nav.ts |
Target.navigate, URL changes, iframe targeting |
| Observation | driver/observe.ts |
Screenshots, element-center calculation, DOM snapshots |
| Waits | driver/waits.ts |
Load events, selector polling, network idle detection |
Each driver imports cdp() from src/cdp-eval.ts to send commands through the runtime layer.
How Element Resolution Bridges Selectors to CDP Object IDs
AI agents work with human-readable selectors. CDP requires objectId references. src/element-resolver.ts bridges this gap.
The resolver accepts multiple locator syntaxes:
loc=css:.button.primary— CSS selector with explicit prefixxpath=//button[@id='submit']— XPath expression@3— numeric reference to previously resolved element
Resolution failures get classified as transient (element not yet in DOM, retry advised) or permanent (invalid selector, immediate error). This classification powers intelligent retry logic in wait utilities.
Successful resolution returns a CDP-compatible objectId that pointer and keyboard drivers consume directly.
The Automation Flow: From Helper Call to Browser Action
Understanding how ego-browser executes a typical click() call reveals the full stack:
-
Helper invocation —
click('button#submit')insrc/helpers.ts -
Element resolution —
element-resolver.tsparses the CSS selector and queries the DOM viaDOM.querySelector, returning anobjectId -
Focus preparation —
DOM.focusensures the element is interactive -
Pointer dispatch —
driver/pointer.tscalculates coordinates (or uses element-center fromdriver/observe.ts) and sendsInput.dispatchMouseEventwithtype: 'mousePressed'then'mouseReleased' -
Result propagation — Success returns void; failures throw normalized exceptions
Navigation flows differ slightly. goto(url) uses driver/nav.ts to call Target.navigate, then driver/waits.ts polls for Page.loadEventFired or network idle conditions.
Task-Space Isolation for Multi-Agent Safety
AI agents in production require browser context isolation. ego-browser implements task spaces—dedicated browser contexts with separate cookies, localStorage, and tab ownership.
Functions in src/helpers.ts manage this:
newTaskSpace()— creates fresh browser context with unique identifieruseOrCreateTaskSpace(id)— returns existing context or initializes new one- Ownership rules prevent agents from interfering with each other's sessions
This design enables safe concurrent operation without the memory overhead of separate browser instances.
Practical Code Examples for AI Agent Integration
These snippets demonstrate typical ego-browser usage via the CLI or module import:
// Navigate and establish session
await goto('https://example.com');
// Wait for critical element
await waitForSelector('[data-testid="content-loaded"]');
// Interact with form
await fill('input[name="search"]', 'automation tools');
await click('button[type="submit"]');
// Extract data via evaluation
const results = await evaluate(() => {
return Array.from(document.querySelectorAll('.result'))
.map(el => el.textContent);
});
// Capture visual state
await screenshot({ path: 'results.png', fullPage: true });
// Clean task-space when done
await closeTaskSpace();
For programmatic use, import the helpers directly:
import { goto, click, evaluate, newTaskSpace } from '@ego/browser';
async function runAgentTask() {
await newTaskSpace('agent-42');
await goto('https://tasks.example.com');
// ... automation logic
}
Key Implementation Files Reference
| File | Purpose |
|---|---|
src/browser-runtime.ts |
CDP session lifecycle, raw transport |
src/cdp-eval.ts |
Low-level CDP request wrapper, runtimeValue() parsing |
src/helpers.ts |
Public API, task-space utilities |
src/element-resolver.ts |
Selector parsing, objectId resolution |
src/driver/pointer.ts |
Mouse actions, coordinate dispatch |
src/driver/keyboard.ts |
Keystroke simulation, input injection |
src/driver/nav.ts |
URL navigation, frame targeting |
src/driver/observe.ts |
Screenshots, DOM snapshots |
src/driver/waits.ts |
Polling primitives, event awaiting |
Summary
- ego-browser provides lightweight browser automation for AI agents through a three-layer CDP architecture
- The CDP transport layer in
browser-runtime.tshandles session persistence and automatic re-attachment - Helper functions in
helpers.tsexpose a Playwright-like API while managing task-space isolation - Driver modules compose raw CDP commands for pointer, keyboard, navigation, observation, and wait operations
- Element resolution translates human-readable selectors into CDP
objectIdreferences with intelligent failure classification - Task-space primitives enable safe multi-agent concurrency without full browser instance overhead
Frequently Asked Questions
What makes ego-browser different from Playwright or Puppeteer?
ego-browser intentionally minimizes dependencies and abstraction layers. While Playwright bundles multiple browser engines and extensive assertion libraries, ego-browser focuses exclusively on CDP-based Chrome automation with a smaller footprint. This makes it suitable for AI agents running in resource-constrained environments where startup time and memory usage matter.
How does ego-browser handle browser crashes or disconnections?
The browser-runtime.ts module implements transparent re-attachment. When browserCdp() detects a closed session, ensureSession() re-establishes the Target.attachToTarget connection using stored context information. This resilience happens without surfacing errors to AI agent code, allowing continuous operation across transient failures.
Can AI agents use custom Chrome flags or DevTools extensions?
Yes. The embedded ego runtime accepts Chrome startup parameters. Agents can enable specific features by configuring the runtime before helper invocation. However, the public API intentionally abstracts these details—advanced customization requires direct CDP calls through cdp() with domain-specific commands.
What selector strategies perform best with ego-browser's element resolver?
CSS selectors with the loc=css: prefix resolve fastest due to direct DOM.querySelector mapping. XPath expressions work for complex traversals but incur minor parsing overhead. Numeric @N references are fastest when reusing previously located elements across multiple actions, avoiding repeated DOM queries.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →