chrome-agent
Browser automation that speaks LLM.
You're not the user. Your LLM is.
You don't need to read this README. Your agent does. Install it, run
chrome-agent --help, and let the LLM figure it out. The CLI embeds its own usage guide, every error comes with a hint for the next action, and--jsonmode outputs structured data an agent can parse without you writing a single adapter. This page is here because GitHub expects one.
Playwright returns 2,000 tokens of raw HTML. chrome-agent returns 50 tokens of accessibility tree with stable element IDs. No CSS selectors to write, no DOM to parse.
# ~50 tokens instead of ~2,000:
uid=n1
uid=n50
uid=n82
uid=n97
# Click + see the new page in one call:
UIDs are based on Chrome's backendNodeId. They don't change between inspects. Click n82 now or five minutes from now.
chrome-agent (3 MB Rust binary)
| CDP over WebSocket
v
Chrome (headless, no Node.js, no runtime)
Why this exists
| If you've hit this... | chrome-agent does this instead |
|---|---|
| Playwright snapshots burn 2K tokens | a11y tree: ~50 tokens. 40x less context spent on page state. |
| CSS selectors break after every deploy | UIDs from Chrome's backendNodeId. Stable as long as the DOM node exists. |
| Click then inspect = 2 round-trips | --inspect on any command. One call, action + observation. |
| 200MB of Node + npm + Playwright | 3 MB binary. npx chrome-agent works out of the box. |
| Cloudflare blocks your headless Chrome | 7 CDP patches. Runtime.enable never called (the detection vector nobody talks about). |
| Writing per-site scraping selectors | read for articles, extract for lists/tables/cards, network for API payloads. No selectors. |
| Errors are stack traces | {"ok":false, "error":"...", "hint":"run inspect"} -- parseable, actionable. |
| Each command launches a fresh browser | Sessions persist. Chrome stays alive between calls. ~10ms startup. |
| Agent can't access your logged-in accounts | --copy-cookies grabs cookies from your real Chrome. Works with X.com, Gmail, dashboards. |
| Infinite scroll shows 10 items | inspect --scroll --limit 50 scrolls and collects. Tested on X.com: 50 tweets from a live timeline. |
| Two agents sharing one browser = chaos | --browser agent1, --browser agent2. Separate Chrome instances. |
Install
# For AI agents -- installs a SKILL.md your agent reads automatically
# Or just the binary
Quick start
# Navigate and see the page
# Click by uid
# Fill a form
# CSS selectors work too
# Article content (Readability -- like Firefox Reader Mode)
# Visible text, scoped and capped
# Run JS
# Screenshot (returns a file path, not binary)
Commands
| Command | What it does |
|---|---|
goto <url> [--inspect] [--max-depth N] |
Navigate. Auto-prefixes https:// if missing. |
inspect [--verbose] [--max-depth N] [--uid nN] [--filter "role,role"] [--scroll] [--limit N] |
a11y tree with UIDs. --scroll --limit for infinite scroll. |
click <uid> [--inspect] |
Click by uid. Falls back to JS .click() when no box model. |
click --selector "css" [--inspect] |
Click by CSS selector. |
click --xy 100,200 |
Click by coordinates. |
fill --uid <uid> <value> [--inspect] |
Fill input by uid. |
fill --selector "css" <value> |
Fill by selector. |
fill-form <uid=val>... |
Batch fill. |
read [--html] [--truncate N] |
Article extraction via Mozilla Readability. |
text [uid] [--selector "css"] [--truncate N] |
Visible text from page or element. |
eval <expression> [--selector "css"] |
JS in page context. el = matched element. |
extract [--selector "css"] [--limit N] [--scroll] [--a11y] |
Auto-detect repeating data. --a11y for React SPAs (X.com). |
network [--filter "pattern"] [--body] [--live N] |
Network requests and API responses. |
console [--level error] [--clear] |
console.log/warn/error + JS exceptions. |
pipe |
Persistent JSON stdin/stdout connection. |
wait <text|url|selector> <pattern> |
Wait for a condition. |
type <text> [--selector "css"] |
Type into focused element. |
press <key> |
Enter, Tab, Escape, etc. |
scroll <down|up|uid> |
Scroll page or element into view. |
hover <uid> |
Hover. |
back |
History back. |
screenshot [--filename name] |
Screenshot to file. |
tabs |
List open tabs. |
diff |
What changed since last inspect. |
close [--purge] |
Stop browser. --purge deletes cookies/profile. |
status |
Session info. |
stop |
Stop daemon. |
Global flags
--browser <name> Named browser profile (default: "default")
--page <name> Named tab (default: "default")
--connect [url] Attach to a running Chrome
--headed Show browser window (default: headless)
--stealth Anti-detection patches (Cloudflare, Turnstile)
--copy-cookies Use cookies from your real Chrome profile
--timeout <seconds> Command timeout (default: 30)
--max-depth <N> Limit inspect depth
--ignore-https-errors Accept self-signed certs
--json Structured JSON output
The loop: inspect, act, inspect
# uid=n52 textbox "Email" focusable
# uid=n58 textbox "Password" focusable
# uid=n63 button "Sign In" focusable
# uid=n101 heading "Dashboard" level=1
UIDs stay the same between inspects as long as the DOM node exists.
Content extraction
From least to most tokens:
# Articles (Readability, like Firefox Reader Mode)
# Repeating data -- products, search results, feeds. No selectors.
# Uses MDR/DEPTA heuristics. Finds the pattern automatically.
# React SPAs (X.com, etc.) -- uses a11y tree instead of DOM
# Scoped visible text
# API responses -- skip the DOM
Stealth
--stealth patches 7 automation fingerprints via CDP:
navigator.webdriverset toundefinedchrome.runtimemocked- Permissions API fixed
- WebGL renderer masked
- User-Agent cleaned
- Input coordinate leak patched
Runtime.enablenever called
These are CDP-level patches (Page.addScriptToEvaluateOnNewDocument), not Chrome flags.
For sites with heavier protection (DataDome, Kasada) that fingerprint the Chromium binary itself, connect to your real Chrome:
&
| Protection | Solution |
|---|---|
| None | chrome-agent goto ... |
| Cloudflare/Turnstile | chrome-agent --stealth goto ... |
| Logged-in sites | chrome-agent --stealth --copy-cookies goto ... |
| DataDome/Kasada | chrome-agent --connect to real Chrome |
Logged-in sites
--copy-cookies copies the cookie database from your Chrome profile. Both Chrome instances use the same macOS Keychain, so encrypted cookies just work.
# Your timeline. Your DMs. No login flow.
Your real Chrome is not affected.
Network and console capture
# Resources already loaded (stealth-safe, uses Performance API)
# Live traffic with response bodies
# Console output
Console capture uses an injected interceptor, not Runtime.enable.
Pipe mode
For agents that send many commands in sequence, pipe mode keeps a single connection open:
|
One JSON line per response. About 10x faster than spawning a process per command.
JSON mode
# {"ok":true,"url":"...","title":"...","snapshot":"uid=n1 heading..."}
# {"ok":true,"result":2}
# Errors exit 0 so agents can always parse stdout:
# {"ok":false,"error":"Element uid=n99 not found.","hint":"Run 'chrome-agent inspect'"}
Multi-tab and parallel agents
# Multiple tabs in one browser
# Multiple agents, each with their own Chrome
Using with AI agents
# Install the skill (Claude Code, Cursor, Copilot, etc.)
# Or tell your agent to run:
# The help output includes a full LLM usage guide.
Claude Code permissions:
Comparison
| chrome-agent | dev-browser | chrome-devtools-mcp | Playwright MCP | |
|---|---|---|---|---|
| Language | Rust | Rust + Node.js | TypeScript | TypeScript |
| Runtime deps | none | Node + npm + Playwright + QuickJS | Node + Puppeteer | Node + Playwright |
| Binary size | 3 MB | 3 MB CLI + 200 MB deps | npm package | npm package |
| CLI startup | ~10ms (session reuse) | ~500ms | N/A (MCP) | N/A (MCP) |
| Element targeting | uid + selector + coords | selectors + snapshotForAI | uid (sequential) | selectors |
| UID stability | backendNodeId (stable) | N/A | sequential (reassigned) | N/A |
| Action + observe | --inspect (1 call) |
batched script | 1 call per action | 1 call per action |
| Stealth | 7 CDP patches | No | No | No |
| Reader mode | read (Readability) |
No | No | No |
| Network capture | retroactive + live | No | No | metadata only |
| Data extraction | extract (auto-detect) |
No | No | No |
| Console capture | stealth-safe | No | yes | No |
| Pipe mode | yes | No | No | No |
| Code | ~6.2K lines | ~76K lines | ~12K lines | Playwright |
License
MIT