Core Usage
Reading Pages
snapshot turns the page into
an accessibility tree with refs — you click and type based on it; get text
grabs body text across every frame, piercing even closed shadow DOM.
snapshot: a structured view of the page
snapshot generates the page structure from the accessibility tree. By default it prints the full tree (fairly verbose);
in practice you almost always add -i: keep only interactive elements,
each carrying a ref. Pass it as @eN to a following command to act on it.
$ chrome-use snapshot # full tree (verbose)
$ chrome-use snapshot -i # interactive elements only (recommended)
$ chrome-use snapshot -i -u # include href url on links
$ chrome-use snapshot -i -c # compact: drop empty structural nodes
$ chrome-use snapshot -i -d 3 # depth limit of 3 levels
$ chrome-use snapshot --json # machine-readable output
snapshot -i by default. It's small, contains only what you can act on,
and gives stable, usable @ref values — the proper entry point for driving clicks and typing.
Reading snapshot's output
The output is an indented accessibility tree, where indentation represents nesting depth:
Page: Example - Log in
URL: https://example.com/login
- heading "Log in" [level=1, ref=e1]
- textbox "Email" [ref=e2]
- textbox "Password" [ref=e3]
- button "Continue" [ref=e4]
- link "Forgot password?" [ref=e5]
Each line has the format - <role> "<accessible name>" [<attributes>, ref=eN].
Pass the ref as @eN to a command to act on it, for example
click @e4.
ref values are renumbered on every snapshot. Don't cache an old
@eN and reuse it across operations — after the page changes, run snapshot again first and grab the new ref.
Filtering a huge snapshot
Synology DSM, NAS / router admin panels, and ExtJS apps render many independent "application windows"
into a single accessibility tree, and snapshot -i can easily blow past the token limit and
bury the control you want. Don't pipe to tail — narrow it precisely with filters.
$ chrome-use snapshot -s "#main" # scope to one container with a CSS selector
$ chrome-use snapshot -i -f "SSH|端口|应用" # keep matching lines + their ancestors (regex)
-f/--filter <regex> keeps only the matching lines plus their ancestor context,
with refs intact; -s <css> scopes the whole tree to one
window's container. The two can be stacked.
Validation errors show up too
When a form refuses to submit, the reason is appended to the -i output as a top-level
alert line, for example - alert "字数已超过 8 个字" or
- alert "Email is required" — even when the message is just a styled
<span> (.is-error, .invalid-feedback,
[role=alert], aria-live) that -i would otherwise filter out as a
non-interactive element.
alert lines are informational and deliberately carry no ref (you read it, you don't click it).
So when a click submission does nothing, don't guess the reason — just run
snapshot -i again and read those alert lines.
get text: reading body text unstructured
When you don't need a ref and just want to read text, use get text. It can read the whole page, a single element,
skip navigation boilerplate, and even pierce closed shadow DOM.
$ chrome-use get text # whole page — aggregates all frames by default (see below)
$ chrome-use get text @e1 # visible text of a single element (a CSS selector works too)
$ chrome-use get text --main # body only — skips nav / header / sidebar
$ chrome-use get text --pierce # pierce closed shadow DOM (injected panels)
$ chrome-use frames # list each frame + where the text lives
$ chrome-use get html @e1 # innerHTML
$ chrome-use get attr @e1 href # any attribute
$ chrome-use get value @e1 # value of an input
$ chrome-use get title # page title
$ chrome-use get url # current URL
$ chrome-use get count ".item" # count matching elements
Whole-page text spans frames by default
chrome-use get text without a selector aggregates the visible text of every frame
— the top-level document, same-process child frames, and cross-origin iframes — so you won't silently miss
content hidden inside an iframe (Yahoo Auctions / Rakuten / Mercari product descriptions, embedded checkout / spec frames).
Each child frame is delimited by a ----- frame [kind] url ----- marker. You don't need to remember any flag;
it reads all frames by default (--all-frames remains as an explicit alias).
chrome-use get text to read everything. To see the structure (which frame
holds what), run chrome-use frames; to strip boilerplate (global nav/header/footer,
"related products" sidebars), use get text --main. If the content is lazy-loaded, first
scroll it into view before reading.
read: pull a URL as agent-readable text
read [url] fetches a URL and does its best to hand back clean
markdown/text: it prefers a .md version and a nearby
llms.txt, and falls back to readable text extracted from the HTML when neither
exists. Omit the URL and it reads the rendered DOM of the
active tab instead. It has a different job from snapshot/extract:
read pulls human-facing prose/markdown, while
snapshot/extract pull interactive elements / structured data.
$ chrome-use read https://docs.example.com/guide # read a URL
$ chrome-use read https://docs.example.com/guide --outline # just the heading outline
$ chrome-use read # read the active tab
Common flags: --raw (return the response body untouched), --require-md
(fail unless the response is text/markdown), --llms <index|full>
(the nearest llms.txt's index or full view), --outline (heading
outline only), --filter <text> (keep only matching sections/headings), and
--timeout <ms>. --json returns metadata alongside the content.
read https://site/docs/ --llms index
to list the pages its llms.txt advertises (it walks up to the nearest
llms.txt), then read <page> --require-md to demand the
markdown version; without --require-md it falls back to HTML-extracted prose.
--llms can't be combined with --outline.
read. Want
interactive elements to click or type into? Use the snapshot above.
Want structured JSON? Use extract.
eval: running inside a specific frame
eval runs in the main frame by default. It won't silently bind to whatever frame
Chrome happens to return — a bare eval always targets the top-level document. To run inside a child frame
(for example a cross-origin Google account picker), use
--frame <index|url-substring|@ref|css-selector>
(index / url come from chrome-use frames).
$ chrome-use frames # get the index / url first
$ chrome-use eval --frame accounts.google.com "location.href"
Piercing closed shadow DOM
Some injected UIs (a browser extension's debug panel, Web Components) render into a
closed shadow root that eval / innerText can't read.
chrome-use get text --pierce reads through closed shadow roots and child documents via CDP's DOM tree
— use it when the content is clearly on screen (a screenshot shows it) but get text /
eval returns empty.
snapshot -i is built from the accessibility tree, and the AX tree already pierces
closed shadow roots — a closed-shadow <button> /
[role=button] shows up as an ordinary @ref and clicks as usual.
Only a semantically empty clickable <div> inside a closed root
can dodge both the AX tree and the cursor-element scan.
Next steps
Once you understand the page, take those refs and text and do something with them.