Reference
Command Reference
This is the complete cheat sheet of every chrome-use command, alias, and flag. It's organized by command group so it's easy to scan and verify. To get a feel for the overall rhythm first, read the Core Loop; when a command doesn't work, check Troubleshooting.
@e1, @e2 in interaction commands are element references (refs) from
snapshot output. Run snapshot -i first to get the refs, then act on them.
Any command with a @ref always targets the tab that was active when the snapshot ran.
Navigation
Open, navigate, go back/forward, and close the browser. Without a URL, open just launches
the browser and stops at about:blank — handy for registering network interceptors, cookies,
or init scripts before the first real navigation.
# launch the browser only, no navigation; stops at about:blank
$ chrome-use open
# launch and navigate (aliases: goto, navigate); prepends https:// when no protocol
$ chrome-use open <url>
$ chrome-use back # go back
$ chrome-use forward # go forward
$ chrome-use reload # reload
# SPA client-side navigation: auto-detects Next.js router.push, falls back to history.pushState
$ chrome-use pushstate <url>
$ chrome-use close # close the browser (aliases: quit, exit)
$ chrome-use connect 9222 # connect over a CDP port
You can line up all the pre-navigation setup in one shot with batch — launch cleanly, register
interceptors / cookies in order, then navigate. This suits SSR-only debugging (block everything except
--resource-type script), authenticating against a protected origin, or capturing a clean
react suspense / vitals state.
$ chrome-use batch \
'["open"]' \
'["network","route","*","--abort","--resource-type","script"]' \
'["cookies","set","--curl","cookies.curl","--domain","localhost"]' \
'["navigate","http://localhost:3000/target"]'
Snapshot (page analysis)
snapshot gives you a structured accessibility view of the page — the starting point for all
interaction. snapshot -i is recommended: it lists only interactive elements, so the output is
compact and every ref is present.
$ chrome-use snapshot # full accessibility tree
$ chrome-use snapshot -i # interactive elements only (recommended)
$ chrome-use snapshot -c # compact output
$ chrome-use snapshot -d 3 # limit depth to 3
$ chrome-use snapshot -s "#main" # scope to a CSS selector
snapshot -i only surfaces visible, interactive elements — it does not show
hidden inputs or a control's actual submitted value. When a form "looks filled in" but won't pass validation,
don't guess from the snapshot — inspect the DOM directly with eval.
Interactions
Drive the real browser with the @ref values from snapshot: click, type, check, drag, upload.
$ chrome-use click @e1 # click
$ chrome-use click @e1 --new-tab # click and open in a new tab
$ chrome-use dblclick @e1 # double-click
$ chrome-use focus @e1 # focus the element
$ chrome-use fill @e2 "text" # clear then type
$ chrome-use type @e2 "text" # type directly (no clear)
$ chrome-use press Enter # press a key (alias: key)
$ chrome-use press Control+a # key combo
$ chrome-use keydown Shift # hold a key down
$ chrome-use keyup Shift # release a key
$ chrome-use hover @e1 # hover
$ chrome-use check @e1 # check a checkbox
$ chrome-use uncheck @e1 # uncheck
$ chrome-use select @e1 "value" # pick a dropdown option
$ chrome-use select @e1 "a" "b" # multi-select
$ chrome-use scroll down 500 # scroll the page (default down 300px)
$ chrome-use scrollintoview @e1 # scroll element into the viewport (alias: scrollinto)
$ chrome-use drag @e1 @e2 # drag and drop
$ chrome-use upload @e1 file.pdf # upload a file
<li> items often close when the input loses focus. If click
reports success but the page doesn't react, retry that click with AGENT_BROWSER_CLICK_MODE=dom —
DOM dispatch doesn't move focus the way a real pointer does, so the option still gets selected.
Reading information
Read text, HTML, attributes, values, bounding boxes, and computed styles from elements or the page.
$ chrome-use get text @e1 # element text
$ chrome-use get html @e1 # innerHTML
$ chrome-use get value @e1 # input value
$ chrome-use get attr @e1 href # attribute
$ chrome-use get title # page title
$ chrome-use get url # current URL
$ chrome-use get cdp-url # CDP WebSocket URL
$ chrome-use get count ".item" # number of matching elements
$ chrome-use get box @e1 # bounding box
$ chrome-use get styles @e1 # computed styles (font, color, background, etc.)
Check state
$ chrome-use is visible @e1 # is it visible
$ chrome-use is enabled @e1 # is it enabled
$ chrome-use is checked @e1 # is it checked
Screenshots & PDF
$ chrome-use screenshot # save to a temp directory
$ chrome-use screenshot path.png # save to a specific path
$ chrome-use screenshot --full # full-page screenshot
$ chrome-use pdf output.pdf # save as PDF
Headless Chromium hides native scrollbars in screenshots for consistent image output. Pass
--hide-scrollbars false at launch to keep the native scrollbars.
Recording
$ chrome-use record start ./demo.webm # start recording
$ chrome-use click @e1 # perform actions
$ chrome-use record stop # stop and save
$ chrome-use record restart ./take2.webm # stop the current one + start a new recording
Waiting
Wait for an element, text, URL, network idle, or any JS condition before asserting state.
$ chrome-use wait @e1 # wait for an element
$ chrome-use wait 2000 # wait a number of milliseconds
$ chrome-use wait --text "Success" # wait for text (or -t)
$ chrome-use wait --url "**/dashboard" # wait for a URL pattern (or -u)
$ chrome-use wait --load networkidle # wait for network idle (or -l)
$ chrome-use wait --fn "window.ready" # wait for a JS condition (or -f)
Mouse control
$ chrome-use mouse move 100 200 # move the mouse
$ chrome-use mouse down left # press a button
$ chrome-use mouse up left # release a button
$ chrome-use mouse wheel 100 # wheel
Semantic locators
An alternative to refs: locate by role, text, label, placeholder, alt, title, testid, or position, and chain the action to perform directly after it.
$ chrome-use find role button click --name "Submit"
$ chrome-use find text "Sign In" click
$ chrome-use find text "Sign In" click --exact # exact match only
$ chrome-use find label "Email" fill "user@test.com"
$ chrome-use find placeholder "Search" type "query"
$ chrome-use find alt "Logo" click
$ chrome-use find title "Close" click
$ chrome-use find testid "submit-btn" click
$ chrome-use find first ".item" click
$ chrome-use find last ".item" click
$ chrome-use find nth 2 "a" hover
Browser settings
$ chrome-use set viewport 1920 1080 # viewport size
$ chrome-use set viewport 1920 1080 2 # 2x retina (CSS size unchanged, higher-res screenshots)
$ chrome-use set device "iPhone 14" # emulate a device
$ chrome-use set geo 37.7749 -122.4194 # geolocation (alias: geolocation)
$ chrome-use set offline on # toggle offline mode
$ chrome-use set headers '{"X-Key":"v"}' # extra HTTP headers
$ chrome-use set credentials user pass # HTTP basic auth (alias: auth)
$ chrome-use set media dark # emulate color scheme
$ chrome-use set media light reduced-motion # light + reduced motion
Cookies & storage
$ chrome-use cookies # get all cookies
$ chrome-use cookies set name value # set a cookie
$ chrome-use cookies clear # clear cookies
$ chrome-use storage local # all of localStorage
$ chrome-use storage local key # a specific key
$ chrome-use storage local set k v # set a value
$ chrome-use storage local clear # clear everything
Import cookies from cURL
Auto-detects the format: a JSON array of {name, value}, a DevTools → Network → Copy as cURL dump,
or a bare Cookie header. Cookie values are never echoed back on error.
$ chrome-use cookies set --curl <file> # auto-detect JSON / cURL / Cookie header
$ chrome-use cookies set --curl <file> --domain example.com # scope to a domain
Network interception
Intercept, block, mock responses, rewrite requests, or edit real responses. For in-depth usage, see the network section in the Core Loop.
$ chrome-use network route <url> # intercept requests
$ chrome-use network route <url> --abort # block requests
# mock a response (fulfill)
$ chrome-use network route <url> --body '{}' --status 200 --header K=V --content-type application/json
# rewrite a request (continue)
$ chrome-use network route <url> --method POST --set-body '{}' --set-header K=V --rewrite-url <u>
# edit a real response
$ chrome-use network route <url> --edit-status 503 --edit-header K=V --replace 'from=>to'
$ chrome-use network unroute [url] # remove a route
$ chrome-use network requests # view tracked requests
$ chrome-use network requests --filter api # filter requests
Intercept by resource type
# block scripts only (SSR-lock mode)
$ chrome-use network route '*' --abort --resource-type script
# replace images and fonts with empty responses
$ chrome-use network route '*' --resource-type image,font --body ''
Tabs & windows
Tab ids are stable strings like t1, t2 and are not reused within a session.
Positional integers are not accepted — tab 2 errors; use t2.
You can also give a tab a readable label (docs, app), interchangeable with the id.
$ chrome-use tab # list tabs (with tabId and label)
$ chrome-use tab new [url] # new tab
$ chrome-use tab new --label docs [url] # new tab with a readable label
$ chrome-use tab t2 # switch by id
$ chrome-use tab docs # switch by label
$ chrome-use tab close # close the current tab
$ chrome-use tab close t2 # close by id
$ chrome-use tab close docs # close by label
$ chrome-use window new # new window
@eN belongs to the tab that was active when the
snapshot ran. To operate on another tab, switch to it first, then snapshot. Labels are never
auto-generated, aren't rewritten after navigation, and are unique within a session.
Frames (iframe)
iframes are detected automatically during a snapshot, and their contents are inlined beneath the iframe element (one level of nesting). refs inside an iframe can be operated on directly; you can also switch frame context for a scoped snapshot.
$ chrome-use frame "#iframe" # switch to an iframe by CSS selector
$ chrome-use frame @e3 # switch to an iframe by element ref
$ chrome-use frame main # return to the main frame
frame accepts three kinds of input: an element ref (frame @e3),
a CSS selector (frame "#payment-iframe"), and a
frame name / URL (matched against the browser's frame tree).
Dialogs
By default alert and beforeunload are accepted automatically so the agent doesn't
block; confirm and prompt still need explicit handling. Use --no-auto-dialog
to turn that behavior off.
$ chrome-use dialog accept [text] # accept the dialog
$ chrome-use dialog dismiss # dismiss the dialog
$ chrome-use dialog status # check whether a dialog is open
Running JavaScript
eval runs in the page's MAIN world, so state persists and handlers fire.
When your code contains nested quotes or special characters, -b / --stdin is more
reliable — shell escaping is easy to get wrong.
$ chrome-use eval "document.title" # simple expressions only
$ chrome-use eval -b "<base64>" # arbitrary JS (base64-encoded)
$ chrome-use eval --stdin # read the script from stdin
# multi-line scripts via stdin + heredoc:
$ cat <<'EOF' | chrome-use eval --stdin
const links = document.querySelectorAll('a');
Array.from(links).map(a => a.href);
EOF
Debug forms / hidden state with eval
# dump every field's name → value, including hidden inputs and unchecked radios
$ chrome-use eval "JSON.stringify([...document.forms[0].elements].map(e=>({name:e.name,type:e.type,value:e.value,checked:e.checked})).filter(e=>e.name))"
# why won't it submit? ask the browser's own validity API
$ chrome-use eval "[...document.forms[0].elements].filter(e=>!e.validity?.valid).map(e=>e.name+': '+e.validationMessage)"
Single-pass scripting (batch / script)
Multi-step flows don't need one round-trip per command. batch runs a fixed sequence in one round-trip;
script adds values between steps, loops, conditions, and asserts. See Single-pass Scripting.
# JSON op-list: value bus {{name.path}} + waitUntil/forEach/assert/return, --dry-run to validate
$ chrome-use script prog.json
$ chrome-use script - --dry-run < prog.json
# JS form: a synchronous JS program driven by cu.* helpers (ego's code-base idiom)
$ chrome-use script --timeout 120000 <<'JS'
cu.open('https://news.ycombinator.com');
const rows = cu.eval("[...document.querySelectorAll('.athing')].length");
return { count: rows };
JS
Options: --timeout <ms>, --dry-run (validate the JSON program only), --yes (auto-confirm inside the script),
--arg k=v (seed a variable). Exit codes: 0 ok, 1 runtime failure or failed assert, 2 invalid program.
State management
$ chrome-use state save auth.json # save cookies, storage, and auth state
$ chrome-use state load auth.json # restore saved state
Init scripts
$ chrome-use open --init-script <path> # register before the first navigation (repeatable)
$ chrome-use addinitscript <js> # register at runtime (returns an identifier)
$ chrome-use removeinitscript <id> # remove a registered init script
React / Web Vitals
The react ... commands require launching with --enable react-devtools;
vitals and pushstate are framework-agnostic.
$ chrome-use open --enable react-devtools <url> # launch with the React hook
$ chrome-use react tree # full component tree
$ chrome-use react inspect <fiberId> # props / hooks / state / source
$ chrome-use react renders start # start recording re-renders
$ chrome-use react renders stop [--json] # stop and print the render analysis
$ chrome-use react suspense [--only-dynamic] [--json] # Suspense boundaries + classifier
$ chrome-use vitals [url] [--json] # LCP/CLS/TTFB/FCP/INP + hydration
$ chrome-use pushstate <url> # SPA client-side navigation (auto-detects Next router)
Debugging
console / errors capture is off by default — an active CDP
Runtime domain is a detectable bot signal. Start the session with
AGENT_BROWSER_CAPTURE_CONSOLE=1 when you need it.
$ chrome-use --headed open example.com # show the browser window
$ chrome-use --cdp 9222 snapshot # connect over a CDP port
$ chrome-use connect 9222 # alternative: the connect command
$ chrome-use console # view console messages (needs AGENT_BROWSER_CAPTURE_CONSOLE=1)
$ chrome-use console --limit 20 # only the last 20 console messages
$ chrome-use console --clear # clear the console
$ chrome-use errors # view page errors (needs AGENT_BROWSER_CAPTURE_CONSOLE=1)
$ chrome-use errors --clear # clear errors
$ chrome-use diagnose # why is the page blank: checks asset 404/MIME + mount state
$ chrome-use highlight @e1 # highlight an element
$ chrome-use inspect # open DevTools for this session
$ chrome-use trace start # start recording a trace
$ chrome-use trace stop trace.zip # stop and save
$ chrome-use profiler start # start profiling
$ chrome-use profiler stop trace.json # stop and save the profile
Find pages the user saved (find-url)
Search local Chrome/Edge bookmarks by keyword — for internal systems or previously saved
pages that public search can't reach. Reads locally; no browser / daemon required. Results are sorted by
most recently added, and javascript: / data: bookmarks are skipped.
$ chrome-use find-url jira board # all keywords must match (name or url)
$ chrome-use find-url --limit 10 invoices
$ chrome-use find-url --browser edge --profile "Profile 1" wiki
$ chrome-use find-url grafana --json # {results:[{name,url,folder}], count}
Drive your real logged-in Chrome (extension)
Chrome 136 locked down --remote-debugging-port on the default profile, so to drive the user's
existing logged-in window, chrome-use goes through a Chrome extension + native
messaging — no port, no token, no per-use confirmation. A one-time install writes the native messaging host
manifest:
$ chrome-use extension install # write the native messaging host manifest (one-time)
$ chrome-use extension connect # auto-attach to the real logged-in tabs
$ chrome-use tab # list the real tabs it now controls
$ chrome-use tab t3 # switch the session to one of them
$ chrome-use snapshot -i # drive it like any normal session
$ chrome-use extension status # is the host installed?
$ chrome-use extension uninstall # remove the host manifest
knfcmbamhjmaonkfnjhldjedeobeafmk).
A loaded unpacked dev build can be disabled / dropped when Chrome restarts, silently breaking the relay — use
the Store build for unattended scenarios.
--extension <path> is unrelated — that loads an extension into a
freshly launched browser.
Global options
These flags go before the command and apply to the whole session. Note: headless mode is forbidden
(a bot signal) — it's headed by default and always (stealth); on a display-less server, use
AGENT_BROWSER_ALLOW_HEADLESS=1.
$ chrome-use --session <name> ... # isolated browser session
$ chrome-use --json ... # JSON output, easy to parse
$ chrome-use --headed ... # default and always on (stealth)
$ chrome-use --full ... # full-page screenshot (-f)
$ chrome-use --cdp <port> ... # connect over CDP
$ chrome-use -p <provider> ... # cloud browser provider (--provider)
$ chrome-use --proxy <url> ... # use a proxy server
$ chrome-use --proxy-bypass <hosts> # hosts that bypass the proxy
$ chrome-use --headers <json> ... # HTTP headers scoped to the URL origin
$ chrome-use --executable-path <p> # custom browser executable
$ chrome-use --extension <path> ... # load an extension (repeatable)
$ chrome-use --ignore-https-errors # ignore SSL certificate errors
$ chrome-use --hide-scrollbars false # keep native scrollbars in headless Chromium screenshots
$ chrome-use --help # help (-h)
$ chrome-use --version # version (-V)
$ chrome-use <command> --help # detailed help for a command
Environment variables
AGENT_BROWSER_SESSION="mysession" # default session name
AGENT_BROWSER_EXECUTABLE_PATH="/path/chrome" # custom browser path
AGENT_BROWSER_EXTENSIONS="/ext1,/ext2" # comma-separated extension paths
AGENT_BROWSER_INIT_SCRIPTS="/a.js,/b.js" # comma-separated init script paths
AGENT_BROWSER_ENABLE="react-devtools" # comma-separated built-in init features
AGENT_BROWSER_HIDE_SCROLLBARS="false" # keep native scrollbars
AGENT_BROWSER_PROVIDER="browserbase" # cloud browser provider
AGENT_BROWSER_STREAM_PORT="9223" # override the WebSocket stream port
AGENT_BROWSER_HOME="/path/to/chrome-use" # custom install location
AGENT_BROWSER_CLICK_MODE="dom" # click strategy: ""(default) / "coord" / "dom"
Stealth / anti-detection knobs (fork)
AGENT_BROWSER_CAPTURE_CONSOLE="1" # enable console/errors capture (off by default; the Runtime domain is a bot signal)
AGENT_BROWSER_TIMEZONE="Asia/Tokyo" # --launch only. native timezone override (IANA id or "auto")
AGENT_BROWSER_BLOCK_WEBRTC="1" # --launch only. hide the local IP via WebRTC
AGENT_BROWSER_HIDE_CANVAS="1" # --launch only. session-stable canvas/audio fingerprint noise
AGENT_BROWSER_ADAPTIVE_REF="0" # disable adaptive @ref relocation (on by default)
{"messages":[]} / {"errors":[]} plus a
hint until you start the session with AGENT_BROWSER_CAPTURE_CONSOLE=1 — this keeps the
CDP Runtime domain disabled on the common automation paths. When something doesn't work, cross-check
Troubleshooting.