| name | chrome-agent |
| description | Browser automation for AI agents. Use when the user asks to interact with websites, scrape data, fill forms, take screenshots, or automate any browser task. Triggers on "open a website", "go to", "scrape", "fill the form", "click", "take a screenshot", "read this page", "search on", "check this site". |
| metadata | {"author":"sderosiaux","version":"0.6.0","tags":["browser","automation","scraping","chrome","cdp"]} |
chrome-agent — Browser Automation
Use chrome-agent to control Chrome for the user. Single binary, zero dependencies, headless by default.
Install Check
which chrome-agent || npm install -g chrome-agent
If install fails (no prebuilt binary), build from source:
cargo install chrome-agent
Core Workflow
inspect → read uids → act → inspect again
chrome-agent goto https://example.com --inspect
chrome-agent click n12 --inspect
chrome-agent fill --uid n20 "value"
chrome-agent click --selector "button.submit"
chrome-agent fill --selector "input[name=email]" "hello@test.com"
Content Extraction (choose the right tool)
| Tool | When | Tokens |
|---|
chrome-agent read | Articles, blog posts, product pages | ~200-500 |
chrome-agent extract | Repeating data: product grids, news feeds, tables, search results | ~100-500 |
chrome-agent text --selector "main" | Scoped visible text | ~500-1000 |
chrome-agent eval "JSON.stringify(...)" | Structured data from DOM | Varies |
chrome-agent inspect --filter "link" --urls | Find links with their href URLs | ~50-200 |
chrome-agent text | Full page text (last resort) | ~5000+ |
Bot Protection
| Site protection | Solution |
|---|
| None | chrome-agent goto ... |
| Cloudflare/Turnstile | chrome-agent --stealth goto ... |
| Logged-in sites (X, Gmail, etc.) | chrome-agent --stealth --copy-cookies goto ... |
| DataDome/Kasada (Leboncoin, etc.) | Connect to real Chrome: see below |
For heavy protection:
google-chrome --remote-debugging-port=9222 &
chrome-agent --connect http://127.0.0.1:9222 goto https://protected-site.com --inspect
Key Commands
chrome-agent goto <url> [--inspect] [--wait-for "selector"] [--header "K: V"]
chrome-agent back
chrome-agent forward
chrome-agent scroll down|up|<uid>
chrome-agent wait network-idle [--idle-ms N] [--timeout N]
chrome-agent inspect [--max-depth N] [--filter "button,link"] [--uid nN] [--urls]
chrome-agent inspect --filter "link" --urls
chrome-agent inspect --filter "article" --scroll --limit 50
chrome-agent inspect --max-chars 4000 [--offset 4000]
chrome-agent click <uid> [--inspect]
chrome-agent click --selector "css" [--inspect]
chrome-agent click --xy 100,200
chrome-agent dblclick <uid> [--inspect]
chrome-agent fill --uid <uid> <value>
chrome-agent fill --selector "css" <value>
chrome-agent fill-form n20="a@b.com" n30="password"
chrome-agent type "text" [--selector "input.search"]
chrome-agent press Enter|Tab|Escape
chrome-agent select --uid <uid> "Option text"
chrome-agent select --selector "#country" "France"
chrome-agent check <uid>
chrome-agent check --selector "input[name=agree]"
chrome-agent uncheck <uid>
chrome-agent upload --uid <uid> /path/to/file.pdf
chrome-agent upload --selector "input[type=file]" /path/to/file.pdf
chrome-agent drag <from-uid> <to-uid>
printf '%s\n' \
'{"cmd":"frame","target":"iframe[src*=\"checkout\"]"}' \
'{"cmd":"inspect"}' \
'{"cmd":"fill","uid":"n42","value":"..."}' \
'{"cmd":"frame","target":"main"}' | chrome-agent pipe
chrome-agent read [--truncate N]
chrome-agent extract [--selector "css"] [--limit N]
chrome-agent extract --scroll
chrome-agent extract --a11y --scroll --limit 20
chrome-agent text [--selector "main"] [--truncate N]
chrome-agent eval "expression" [--selector "css"]
chrome-agent network [--filter "pattern"] [--body] [--limit N]
chrome-agent network --live 5 --body --filter "graphql"
chrome-agent network --abort "*tracking*" --live 30
chrome-agent console [--level error] [--clear]
echo '[{"cmd":"goto","url":"..."},{"cmd":"inspect"},{"cmd":"click","uid":"n12"}]' | chrome-agent batch
echo '{"cmd":"goto","url":"...","inspect":true}' | chrome-agent pipe
chrome-agent screenshot [--filename name] [--format jpeg] [--quality N] [--max-width N] [--uid nN|--selector "css"]
chrome-agent pdf [--filename name] [--landscape] [--background]
chrome-agent download <url> [--out path]
chrome-agent diff
chrome-agent wait text|url|selector "pattern" [--timeout N]
chrome-agent tabs
chrome-agent close [--purge]
Global Flags
--stealth
--json
--page <name>
--max-depth N
--headed
--connect URL
--copy-cookies
--dialog MODE
--dialog-text
JS dialogs (alert/confirm/prompt/beforeunload) are auto-accepted by default so the page never hangs. Use --dialog dismiss to cancel them.
JSON Output Format
All commands with --json return objects on stdout. Errors exit 1 but JSON is still on stdout.
Success: {"ok":true, ...command-specific fields...}
Error: {"ok":false, "error":"message", "hint":"what to do next"}
Per-command shapes:
goto --inspect → {"ok":true, "url":"...", "title":"...", "snapshot":"uid=n1..."}
inspect → {"ok":true, "snapshot":"uid=n1 heading..."}
click/fill/select/check --inspect → {"ok":true, "message":"Clicked...", "snapshot":"..."}
click/fill/select/check (no inspect) → {"ok":true, "message":"Clicked uid=n12"}
read → {"ok":true, "title":"...", "text":"article content..."}
text → {"ok":true, "text":"visible text..."}
eval → {"ok":true, "result": <any JSON value>}
network → {"ok":true, "requests":[{"url":"...", "status":200, ...}]}
console → {"ok":true, "messages":[{"level":"error", "message":"..."}]}
batch → {"ok":true, "results":[...one result per command...]}
screenshot/pdf → {"ok":true, "path":"/path/to/file"}
download → {"ok":true, "path":"...", "bytes":N, "mime":"..."}
inspect --max-chars → adds {"total_chars":N, "truncated":bool, "next_offset":N|null}
Token Budget
An inspect of a typical page is ~50-200 tokens. To stay lean:
--max-depth 2 for deep pages (limits tree to 2 levels)
--filter "button,link" to see only interactive elements (~10-30 tokens)
--filter "link" --urls when deciding which link to follow
read --truncate 1000 caps article extraction
text --selector "main" --truncate 500 for scoped visible text
Important Rules
- Always inspect before interacting — UIDs change when the page mutates.
- After SPA navigation (back, forward, client-side routing), re-inspect — UIDs change on re-render.
- For SPA detail pages, prefer
goto <direct-url> over click — click may open a modal.
- Use
read for articles, text --selector for scoped extraction, eval for structured data.
- Prefer inspect over screenshot — ~50 tokens vs ~100K tokens.
- UIDs are stable (n47, n123) across inspects on the same page — based on backendNodeId.
- --json errors exit 1 with
{"ok":false} on stdout — parseable, check ok field.
- --max-depth works everywhere — on standalone inspect AND on goto/click/fill --inspect.
- Use --filter to find elements fast:
inspect --filter "button,link,textbox".
- Use --urls on inspect to get link destinations:
inspect --filter "link" --urls.
- check/uncheck are idempotent — "Already checked" if no change needed. Prefer over click for checkboxes.
- select works by value or text —
select --uid n5 "Option 2" tries option.value first, then option.text.
- frame is pipe/batch-only —
frame scopes eval+inspect to the iframe, but the binding lives on the connection, so it only persists inside one pipe/batch process (not across separate CLI calls). After switching, inspect for iframe uids then act by uid; --selector still hits the top document. frame main returns.
- batch for multi-step sequences — pipe JSON array to stdin. Faster than separate CLI calls. UIDs from inspect are valid within the same batch.
- close --purge deletes browser profile (cookies, cache) when done.
- Parallel agents: use
--browser <unique-name> to isolate sessions.
- download is auth-preserving — it fetches inside the page so logins carry over. It can't capture a click-triggered browser download; get the href with
inspect --urls and pass the URL.
- wait network-idle over sleeps — for SPA/XHR settle,
wait network-idle is deterministic; avoid guessing fixed timeouts.
- screenshots can be large — prefer
--format jpeg --max-width 1024 or --uid/--selector to keep files (and any re-read tokens) small.