How to Use the ego-browser Node.js CLI for Browser Automation

The ego-browser Node.js CLI executes JavaScript heredocs inside the ego-lite runtime, automatically injecting browser automation helpers that enable navigation, interaction, and screenshotting without boilerplate setup.

The ego-browser package from the citrolabs/ego-lite repository provides a lightweight command-line interface for automating browser tasks. Unlike traditional automation frameworks that require verbose configuration, this tool runs scripts via standard input heredocs and injects a comprehensive set of helpers directly into the execution scope. This architecture enables rapid scripting for web scraping, testing, and workflow automation using nothing but JavaScript and shell commands.

Understanding the CLI Architecture

The CLI entry point at src/run.ts handles the heavy lifting of script execution. When you invoke ego-browser nodejs, the tool reads the heredoc input, constructs an async function wrapper, and injects the helper context assembled in src/helpers.ts. This context exposes high-level actions such as openOrReuseTab, click, snapshotText, and captureScreenshot, along with low-level Chrome DevTools Protocol (CDP) access via src/cdp-eval.ts and src/browser-runtime.ts.

The runtime maintains a ref map that tracks DOM elements between commands. When snapshotText() executes, it refreshes this map and generates stable @N references that survive DOM mutations, allowing reliable interaction even with dynamic web applications. Under the hood, src/element-resolver.ts handles selector resolution across multiple formats—CSS, XPath, @N syntax, and loc= coordinates—while automatically retrying transient failures.

The Three-Step Automation Workflow

Every automation session follows a consistent lifecycle managed through task spaces.

1. Initialize a Task Space with useOrCreateTaskSpace

A task space is an isolated browsing context that persists login state and cookies across script executions. Create or reconnect to one using the helper exported from src/helpers.ts:

const task = await useOrCreateTaskSpace('unique-task-name')

This returns a task object containing an id used for subsequent management calls.

2. Execute Automation Scripts

Once initialized, scripts execute within the ego-lite runtime with full access to browser helpers. Pass your JavaScript via heredoc syntax:

ego-browser nodejs <<'EOF'
  // Automation code here
EOF

Inside the heredoc, call helpers like openOrReuseTab(url, { wait: true }) to navigate, or snapshotText() to capture the semantic DOM structure and populate the ref map for interaction.

3. Terminate the Session with completeTaskSpace

When automation finishes, explicitly close the task space to release resources:

await completeTaskSpace(task.id, { keep: false })

Pass { keep: true } to leave the browser page open for manual inspection.

Core Browser Automation Helpers

The helper context defined in src/helpers.ts exports these primary functions:

  • openOrReuseTab(url, options) – Navigates to URLs or activates existing tabs
  • click(selector, options) – Interacts with elements using CSS, XPath, @N refs, or loc= coordinates
  • snapshotText() – Captures accessible text and visual layout, refreshing the ref map
  • captureScreenshot() – Saves viewport or full-page images
  • js(code) – Executes arbitrary JavaScript in the page context
  • cdp(method, params) – Sends raw CDP commands through src/cdp-eval.ts
  • cliLog(message) – Prints structured output to stdout
  • waitForLoad() – Pauses execution until network idle

Practical CLI Examples

The following patterns demonstrate complete automation cycles using the heredoc syntax documented in skills/ego-browser/SKILL.md.

Capturing Screenshots

This script opens a page, waits for load completion, captures the viewport, and logs the file path:

ego-browser nodejs <<'EOF'
const task = await useOrCreateTaskSpace('example screenshot')
await openOrReuseTab('https://example.com', { wait: true })
const img = await captureScreenshot()
cliLog('Screenshot saved: ' + img.path)
await completeTaskSpace(task.id, { keep: false })
EOF

Clicking Elements and Extracting Data

Using @N references generated by snapshotText provides resilient selectors for dynamic content:

ego-browser nodejs <<'EOF'
await useOrCreateTaskSpace('login flow')
await openOrReuseTab('https://login.example.com', { wait: true })
await snapshotText()               // populates @N refs
await click('@23', { label: 'Click Sign‑In' })
await waitForLoad()
const data = await js(String.raw`() => {
  const el = document.querySelector('#user-info')
  return { name: el?.innerText }
}`)
cliLog('User name: ' + data.name)
await completeTaskSpace(task.id, { keep: false })
EOF

Executing Raw CDP Commands

For advanced scenarios such as configuring download behavior, invoke CDP methods directly through the runtime:

ego-browser nodejs <<'EOF'
await useOrCreateTaskSpace('download pdf')
await openOrReuseTab('https://files.example.com/report.pdf')
await cdp('Page.setDownloadBehavior', {
  behavior: 'allow',
  downloadPath: '/tmp'
})
await cdp('Page.reload')
cliLog('Download started')
await completeTaskSpace(task.id, { keep: false })
EOF

Selector Resolution and Error Handling

The src/element-resolver.ts module provides robust element location across multiple identifier types. When calling click() or similar methods, the resolver attempts matches in this priority: explicit @N refs from the latest snapshotText(), loc= coordinates, standard CSS selectors, and XPath expressions.

The resolver distinguishes between transient failures (network latency, animation frames) and permanent errors (missing elements). It automatically retries transient issues with exponential backoff, eliminating the need for manual sleep statements in scripts. Classification logic in src/element-resolver.ts analyzes error codes and DOM stability signals to determine retry eligibility.

Summary

  • The ego-browser Node.js CLI executes heredoc scripts via src/run.ts, injecting automation helpers from src/helpers.ts automatically.
  • Automation follows a three-step lifecycle: create a task space with useOrCreateTaskSpace, execute commands, then close with completeTaskSpace.
  • Helper functions include openOrReuseTab, click, snapshotText, captureScreenshot, and raw CDP access via cdp().
  • Selector flexibility supports CSS, XPath, @N references, and loc= coordinates, with automatic resolution in src/element-resolver.ts.
  • The runtime handles transient error retries automatically, while src/browser-runtime.ts manages CDP transport and session state.

Frequently Asked Questions

How do I pass variables from my shell environment into the ego-browser script?

Environment variables are not automatically exposed inside the heredoc execution context. Instead, interpolate values directly in the shell before the heredoc opens, or use Node.js process.env access if you export variables before invoking the CLI. For sensitive data, pass values as literal strings in the heredoc content rather than through global scope.

Can I reuse the same task space across multiple separate CLI invocations?

Yes. Call useOrCreateTaskSpace('my-task') with an identical name in subsequent heredocs to reconnect to the existing browsing context. The task space preserves cookies, localStorage, and session state. Remember to call completeTaskSpace(id, { keep: false }) only when you want to destroy the context permanently.

What is the difference between snapshotText() and captureScreenshot()?

snapshotText() captures the semantic DOM structure as accessible text and generates the @N reference map used for reliable element targeting, but produces no image files. captureScreenshot() generates actual PNG images of the viewport or full page using CDP commands. Most automation workflows call snapshotText() before interactions to establish stable selectors, then captureScreenshot() afterward to document visual state.

How does the CLI handle element locations that change between page loads?

The ref map refreshes every time you invoke snapshotText(), assigning new @N identifiers based on the current DOM structure. Additionally, src/element-resolver.ts implements automatic retry logic for transient failures caused by animations or loading states. For elements with dynamic positions, combine snapshotText() immediate usage with the loc= coordinates or prefer stable CSS selectors when available.

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 →