# How to Use CDP Evaluation APIs in ego-browser: Complete Guide

> Learn to use CDP evaluation APIs in ego-browser. This guide shows how to control the embedded browser and extract data using cdp() and evaluate() helpers in your scripts.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: how-to-guide
- Published: 2026-07-27

---

**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](https://github.com/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`](https://github.com/citrolabs/ego-lite/blob/main/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`](https://github.com/citrolabs/ego-lite/blob/main/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`](https://github.com/citrolabs/ego-lite/blob/main/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 via `serializedArg`.
- If a **string** is supplied, the raw string is used directly.
- When the code contains a top-level `return` statement 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`): Use `cdp()`.
- **Arbitrary JavaScript execution** requiring returned values (e.g., reading DOM properties): Use `evaluate()`.
- **Specific target evaluation** (e.g., background pages): Call `evaluate` with the target's ID as the second argument; the helper automatically handles `Target.attachToTarget` under the hood.

## Practical Implementation Examples

Basic page control using raw CDP commands:

```javascript
// 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:

```javascript
// 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:

```javascript
// 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`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/cdp-eval.ts)** – Core implementation of `cdp`, `evaluate`, result decoding, `runtimeEvaluate`, and utility parsers including `hasReturnStatement`.

- **[`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts)** – Maintains mutable runtime state including `cdpOverride` for testing and network flags; exports the low-level `send` function used by the `cdp` helper.

- **[`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts)** – Re-exports `cdp` and `evaluate` for user scripts, along with related utilities like `decodeUnserializableJsValue` (lines 8–28).

- **[`package/ego-browser/src/driver/waits.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/driver/waits.ts)** – Demonstrates real-world usage of `cdp('Runtime.evaluate')` for network idle detection and conditional waiting.

- **[`package/ego-browser/src/driver/nav.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/driver/nav.ts)** – Shows navigation patterns using `cdp('Page.navigate')` and target management strategies.

## Summary

- **ego-browser** provides two primary CDP evaluation APIs: `cdp()` for raw protocol commands and `evaluate()` for JavaScript execution.
- The `cdp` helper automatically manages network domain state and supports mock overrides via `state.cdpOverride`.
- The `evaluate` helper handles function serialization, automatic IIFE wrapping for return statements, and special value decoding.
- All helpers are re-exported from [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts) for direct use in agent scripts.
- Core implementation files include [`cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/cdp-eval.ts) for logic, [`state.ts`](https://github.com/citrolabs/ego-lite/blob/main/state.ts) for state management, and [`driver/waits.ts`](https://github.com/citrolabs/ego-lite/blob/main/driver/waits.ts) for 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')`.