How the Snapshot Mechanism Works in ego-browser: Configuration and Implementation
The ego-browser snapshot mechanism captures a semantic DOM view via the ego bridge, processes it through observe.snapshotRaw in src/driver/observe.ts, and maintains numeric reference mappings (@N) through automatic ref-map synchronization, with configurable options like maxResultLength and includeRefs to control payload size and content.
The snapshot mechanism in ego-browser serves as the primary interface for delivering structured, semantic representations of web pages to automation agents. As implemented in the citrolabs/ego-lite repository, this architecture bridges the JavaScript runtime with a closed-source ego-lite binary to capture DOM state, compute stable locators, and manage ephemeral numeric references. Understanding how snapshotRaw processes requests and which configuration options tune the output is essential for building efficient browser automation scripts.
Core Components of the Snapshot Architecture
The snapshot workflow relies on three tightly-coupled components that manage data capture, public API exposure, and reference state maintenance.
The Observation Layer (src/driver/observe.ts)
At the lowest level, observe.snapshotRaw calls the underlying ego bridge via browserEgo().snapshot(options). This method returns the low-level snapshot object containing content, refs, and metadata. The bridge communicates with the CDP-style ego-lite binary that captures the complete DOM structure and assigns stable numeric identifiers to nodes.
Public Helper Interface (src/helpers.ts)
The helpers.snapshot and helpers.snapshotRaw methods expose snapshot functionality to agent scripts. While snapshotRaw returns the full structured payload including reference mappings, snapshot extracts only the human-readable text content from the content field that agents most commonly consume.
Reference State Management (src/ref-state.ts)
The ensureRefMapForRef function guarantees that the ref map (numeric @N identifiers) remains populated and synchronized. If a script requests a reference before any snapshot exists, this routine triggers a fresh snapshot via the callback registered with registerSnapshotForRefRefresh, ensuring references always point to current DOM nodes.
How the Snapshot Execution Flow Works
When an agent requests a snapshot, the runtime executes a three-step pipeline:
-
Invoke the Bridge – The system awaits
browserEgo().snapshot(options), which communicates with the ego-lite binary to capture the current DOM state, compute stable locators, and assign numeric snapshot refs (@1,@2, etc.). -
Refresh the Ref Map – The raw snapshot passes to
registerSnapshotForRefRefresh, which stores a re-executable callback. This mechanism keeps the reference map synchronized whenever the page navigates or mutates. -
Return Processed Results –
snapshotRawforwards the complete object, while thesnapshothelper extracts thecontentfield for text-only consumption.
Configuration Options for ego-browser Snapshots
The observe.snapshotRaw method accepts an optional SnapshotOptions argument that passes directly to the ego bridge. These controls determine payload size, content inclusion, and performance characteristics.
Size and Performance Controls
maxResultLength(number, default:Infinity): Truncates the returned text content to a specified character count, preventing oversized payloads on large pages.maxBytes(number, default:Infinity): Caps the total byte size of the raw snapshot, including the refs map. The bridge drops excess data rather than throwing exceptions.
Content Inclusion Flags
includeRefs(boolean, default:true): When set tofalse, the snapshot omits therefsmap, producing a lighter payload when numeric references are unnecessary.includeInvisible(boolean, default:false): Controls whether invisible DOM nodes appear in the snapshot. Setting totrueincludes hidden elements, while the default filters to visible content only.includeScreenshot(boolean, default:false): Reserved for future extensions, this option requests a base64-encoded screenshot of the page (currently ignored by the bridge).
These options are documented in the public helper signatures located in src/format.ts, which powers the runtime's help() command.
Understanding Snapshot References (Ref Map)
Ref identifiers (@1, @2, etc.) are short-lived numeric handles that point to stable DOM nodes across multiple script execution rounds. The RefMap rebuilds whenever a snapshot occurs, but ensureRefMapForRef provides automatic refresh guarantees. If a script attempts to use a reference after navigation or DOM mutation without an intervening snapshot, the system implicitly triggers a fresh snapshot to maintain reference validity.
Practical Implementation Examples
Basic text extraction:
// Simple text snapshot – the most common use case
const txt = await page.snapshot(); // → string with page text
console.log(txt);
Structured snapshot with custom limits:
// Structured snapshot with custom limits
const raw = await page.snapshotRaw({
maxResultLength: 2000, // return only the first 2 k characters
maxBytes: 50000, // abort if the raw object would exceed 50 kB
includeRefs: true, // keep numeric @N refs for later reuse
});
console.log(raw.content); // human-readable text
console.log(raw.refs); // map of @N → element handles
Reference refresh after navigation:
// Refreshing a ref after navigation
await page.navigate('https://example.com');
const link = await page.$('a.some-link'); // uses a locator, not a ref
await link.click(); // triggers navigation
// The next line implicitly forces a new snapshot because we will request a ref
await page.$('@12'); // numeric ref – ensures fresh snapshot
Visibility filtering:
// Limiting to visible elements only (default)
const visibleSnap = await page.snapshotRaw({
includeInvisible: false,
});
Summary
- The snapshot mechanism in ego-browser relies on
observe.snapshotRawinsrc/driver/observe.tsto interface with the ego-lite binary viabrowserEgo().snapshot(). - Configuration options include
maxResultLength,maxBytes,includeRefs,includeInvisible, andincludeScreenshotto control payload size and content. - The ref map system in
src/ref-state.tsautomatically maintains numeric@Nidentifiers throughensureRefMapForRefandregisterSnapshotForRefRefresh. - Public helpers in
src/helpers.tsprovide both full structured data (snapshotRaw) and text-only extraction (snapshot). - References remain stable across navigation because the system implicitly refreshes snapshots when stale refs are accessed.
Frequently Asked Questions
What is the difference between page.snapshot() and page.snapshotRaw()?
The page.snapshot() helper returns a string containing only the human-readable text content of the page, while page.snapshotRaw() returns the complete structured object including the content field, refs map, and metadata. According to the implementation in src/helpers.ts, snapshot extracts the text field from the raw result that snapshotRaw provides.
How does ego-browser handle stale references after page navigation?
The system uses ensureRefMapForRef in src/ref-state.ts to guarantee reference validity. When a script accesses a numeric ref (@N) after navigation or DOM mutation, this function automatically triggers a fresh snapshot through the callback registered with registerSnapshotForRefRefresh, rebuilding the ref map to point to current DOM nodes.
Can I exclude invisible DOM elements from the snapshot?
Yes. Set the includeInvisible option to false (the default) when calling snapshotRaw. This filters out hidden elements and returns only visible DOM nodes, keeping the snapshot focused on content that users actually see. Pass true only when automation scripts require access to hidden elements.
Where are the snapshot configuration options documented in the source code?
The SnapshotOptions interface and helper signatures are documented in src/format.ts, which powers the runtime's help() command. The options—maxResultLength, maxBytes, includeRefs, includeInvisible, and includeScreenshot—are passed directly from observe.snapshotRaw to the underlying ego bridge.
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 →