How to Use CDP Evaluation APIs in ego-browser: Complete Guide
The ego-browser harness exposes two core CDP (Chrome DevTools Protocol) helpers—cdp() for raw protocol commands and evaluate() for in-page JavaScript execution—that agents can call directly from their scripts to control the embedded browser and extract data.
The ego-browser package in the citrolabs/ego-lite repository provides low-level CDP evaluation APIs that enable agents to send raw Chrome DevTools Protocol commands and execute JavaScript within page contexts. These capabilities mirror Playwright's low-level API while automatically managing session state and network domain tracking.
Core CDP Evaluation Helpers
Two primary functions handle all CDP interactions in ego-browser:
cdp(method, params?, sessionId?) sends raw CDP commands to the embedded browser. Defined in package/ego-browser/src/cdp-eval.ts (lines 12–25), this helper automatically tracks the default session's network domain state and delegates to state.cdpOverride when testing mocks are installed.
evaluate(pageFunction, arg?) executes JavaScript in the page context, similar to Playwright's page.evaluate. Located in package/ego-browser/src/cdp-eval.ts (lines 28–65), it accepts either a string expression or a serialized function with an optional argument.
Internal Architecture of CDP Evaluation
Command Dispatch Mechanism
The cdp function checks for state.cdpOverride first, falling back to the low-level send helper from package/ego-browser/src/state.ts. After each call, it updates state.networkDomainEnabled when detecting Network.enable or Network.disable commands, allowing higher-level helpers like waitForNetworkIdle to restore previous states.
JavaScript Evaluation Pipeline
When calling evaluate, the helper builds a JavaScript string through several steps:
- If a function is supplied, it stringifies and wraps it as
(${fn})(arg), with arguments JSON-encoded viaserializedArg. - If a string is supplied, the raw string is used directly.
- When the code contains a top-level
returnstatement not already inside an IIFE, it automatically wraps the code in(function(){…})()to guarantee a return value.
The final expression passes to runtimeEvaluate, which internally calls cdp('Runtime.evaluate', …) and processes the raw CDP response through runtimeValue.
Result Handling and Error Decoding
The runtimeValue function inspects CDP responses for exceptions, building helpful error messages via jsExceptionDescription when errors occur. For successful evaluations, it returns result.value or decodes special unserializable values like "NaN" or "Infinity" through decodeUnserializableJsValue.
Utility Helpers
Supporting functions include hasReturnStatement, which parses JavaScript strings to detect top-level returns for correct IIFE wrapping, and serializedArg, which JSON-encodes arguments passed to function-form evaluate calls.
Choosing Between cdp() and evaluate()
Select the appropriate helper based on your automation scenario:
- Raw protocol commands (e.g.,
Page.navigate,Network.enable): Usecdp(). - Arbitrary JavaScript execution requiring returned values (e.g., reading DOM properties): Use
evaluate(). - Specific target evaluation (e.g., background pages): Call
evaluatewith the target's ID as the second argument; the helper automatically handlesTarget.attachToTargetunder the hood.
Practical Implementation Examples
Basic page control using raw CDP commands:
// Reload the current page, ignoring cache
await cdp('Page.reload', { ignoreCache: true });
// Navigate to a new URL and wait for the load event
await cdp('Page.navigate', { url: 'https://example.com' });
await cdp('Page.waitForLoadEvent');
JavaScript evaluation for data extraction:
// Retrieve the page title
const title = await evaluate(() => document.title);
console.log('Page title:', title);
// Execute a function with an argument
const result = await evaluate(
(factor) => document.querySelectorAll('div').length * factor,
3,
);
console.log('Scaled div count:', result);
Evaluating in specific targets:
// Evaluate in a service worker (targetId from Target.getTargets)
const swVersion = await evaluate(
'navigator.serviceWorker.controller.state',
'target-id'
);
console.log('SW state:', swVersion);
Key Source Files and Implementation Details
Understanding the codebase structure helps when extending or debugging CDP evaluation:
-
package/ego-browser/src/cdp-eval.ts– Core implementation ofcdp,evaluate, result decoding,runtimeEvaluate, and utility parsers includinghasReturnStatement. -
package/ego-browser/src/state.ts– Maintains mutable runtime state includingcdpOverridefor testing and network flags; exports the low-levelsendfunction used by thecdphelper. -
package/ego-browser/src/helpers.ts– Re-exportscdpandevaluatefor user scripts, along with related utilities likedecodeUnserializableJsValue(lines 8–28). -
package/ego-browser/src/driver/waits.ts– Demonstrates real-world usage ofcdp('Runtime.evaluate')for network idle detection and conditional waiting. -
package/ego-browser/src/driver/nav.ts– Shows navigation patterns usingcdp('Page.navigate')and target management strategies.
Summary
- ego-browser provides two primary CDP evaluation APIs:
cdp()for raw protocol commands andevaluate()for JavaScript execution. - The
cdphelper automatically manages network domain state and supports mock overrides viastate.cdpOverride. - The
evaluatehelper handles function serialization, automatic IIFE wrapping for return statements, and special value decoding. - All helpers are re-exported from
helpers.tsfor direct use in agent scripts. - Core implementation files include
cdp-eval.tsfor logic,state.tsfor state management, anddriver/waits.tsfor practical usage examples.
Frequently Asked Questions
What is the difference between cdp() and evaluate() in ego-browser?
The cdp() function sends raw Chrome DevTools Protocol commands directly to the browser instance, ideal for navigation and network control. The evaluate() function provides a higher-level abstraction for executing JavaScript within page contexts and returning computed values, handling serialization and error decoding automatically.
How does ego-browser handle return values from evaluate()?
The runtimeValue helper processes CDP responses to extract result.value, decode unserializable JavaScript values like Infinity or NaN, and format exception details via jsExceptionDescription when execution fails. If the evaluated code contains a top-level return statement, the system automatically wraps it in an IIFE to ensure proper value capture.
Can I mock CDP responses when testing with ego-browser?
Yes. The cdp function checks for state.cdpOverride before calling the low-level send helper, allowing test harnesses to install mock implementations. This enables unit testing of agents without requiring an actual browser instance.
How do I execute JavaScript in a specific browser target like a service worker?
Pass the target ID as the second argument to evaluate(). The helper automatically handles Target.attachToTarget under the hood. For example: await evaluate('navigator.serviceWorker.controller.state', 'target-id').
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 →