Core Usage

Reading Pages

For task-specific CLI guidance, load chrome-use skills get core/reading. Ordinary clicks and form actions are already covered by core.

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.

Valid incremental snapshots return JSON refs only for nodes in the delta. A no-change delta has empty refs; the complete live session map and previously captured refs remain available. A full-tree fallback keeps the normal full-snapshot behavior.

read --filter uses literal, ASCII-case-insensitive text matching, not a regex. It prefers matching page headings with their descendants, then matching sections. Use read --outline to find a heading. snapshot --filter separately accepts a regex. read --help lists the reading options.

snapshot: a structured view of the page

After cross-site navigation or reconnecting, page reads use the current document. If the page keeps changing while its private reading context is being recreated, the read fails explicitly; observe the page again before acting.

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.

For scoped, depth-limited, regex-filtered or budgeted snapshots, JSON refs contains only references rendered in the returned excerpt. The session keeps its complete live ref map; narrowing output does not invalidate a previously captured ref. Sparse-page detection still uses the complete map.

snapshot
$ chrome-use snapshot                    # full tree (verbose)
$ chrome-use snapshot -i                 # interactive elements only (recommended)
$ chrome-use snapshot -i -u              # include each link's absolute url (first 400 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 -i --dom            # list actionable elements from a DOM walk (pierces shadow roots)
$ chrome-use snapshot --json             # machine-readable output
✅ Tip
Start with 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.

Interactive snapshots add context only to repeated controls with the same role and name when named parent lines do not already distinguish them. Context omits the control’s own name and punctuation, stays within about 100 characters (60 for unnamed controls), and must differ between controls. Unique controls have no context; use a scoped or full snapshot for missing details such as a unique product’s price.

Keep input focused

Use snapshot -i -c when empty structural nodes add no context, and scope reads to the panel you need. Use a full tree when compact output omits necessary context. Re-read with --diff only when the previous observation leaves a question. Byte counts are not token counts; measure each separately.

Text and refs are the default. For a visual question, add --with-screenshot <path> to a snapshot or observed action to capture pixels alongside the read. Do not capture images on every step when labels and values answer the question. See settling and observation limits.

Reading snapshot's output

The output is an indented accessibility tree, where indentation represents nesting depth:

snapshot -i · example output
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.

⚠️ Note: refs are reassigned every time
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.

filter / narrow
$ 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.

Re-read a page for a few bytes

delta and budget
$ chrome-use snapshot -i --diff            # only what changed since the last snapshot
$ chrome-use snapshot -i --max-bytes 4000  # cut between nodes, report what was omitted
$ chrome-use snapshot -i --max-bytes 4000 --from 70  # read on from where it stopped

After an action, most of the tree is what it was. --diff returns only the lines that changed since this session's last snapshot of the same page, with the same options: on a 143 KB HN comment thread, an unchanged re-read costs 1 byte instead of 143,490. With no valid baseline — no previous snapshot, the page navigated, different options — it returns the full tree and says which, because an empty diff and an unchanged page are indistinguishable.

--max-bytes <n> solves a different problem: unlike -i/-s/-d/-f, a budget needs no advance knowledge of what you are looking for. It cuts only on whole-node boundaries (truncating the string would leave a severed [ref=eN]) and tells you what it left out and where to resume: truncated: nodes 0–70 of 1908 (1838 omitted).

ℹ️ --diff or --observe?
To see what one action changed, use --observe (it rides on the action). To simply look at the page again, use --diff (it rides on snapshot).

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.

ℹ️ Note
These 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.

get
$ 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).

✅ When text looks missing or wrong
Don't guess — just run 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.

read
$ 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
$ chrome-use read https://news.ycombinator.com --links   # plus a "## Links" list: [text](absolute URL)

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), --timeout <ms>, and --links (append a ## Links section with the page's links as absolute URLs, unique, the first 100 by default, --max-links <n> up to 1000; a cut list says how many it left out; a URL over 2048 bytes is omitted and counted, never truncated into a different address; scanning, de-duplication and output are bounded, and a cut makes the count "at least N"). --json returns metadata alongside the content.

ℹ️ A doc-lookup workflow
For an unfamiliar docs site, start with 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 vs. snapshot/extract
Want readable prose (docs, a blog post, a guide)? Use 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).

eval --frame
$ chrome-use frames                                       # get the index / url first
$ chrome-use eval --frame accounts.google.com "location.href"
ℹ️ main world vs. isolated world
A cross-origin (cross-process) frame runs in its own main world; a same-process in-page frame runs in an isolated world (the DOM is readable, but the page JS's global variables are not).

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.

✅ Clicking such controls is good news
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.

Whole page inside shadow roots: automatic DOM-walk fallback

Some web-component SPAs (developer.apple.com/contact, for example) render the entire page inside shadow roots and the accessibility tree comes back with no refs at all. snapshot / snapshot -i then no longer print "(no interactive elements)": they automatically list actionable elements from a DOM.getDocument(pierce:true) walk (open and closed shadow roots, same-process child documents). Those [ref=eN] work with click / type / fill like normal refs; the JSON carries source: "dom" plus a note line, and roles / names are derived from tags and attributes. snapshot --dom forces that path.


Masked values, placeholder selects, errors inside iframes

A field holding a card number, CVC, expiry, password or one-time code shows <filled 19 chars> in snapshot and get value instead of its value (decided by autocomplete, type=password, name/id or the label). Pass --reveal-values only when you need to check the value itself; it then lands in the transcript.

A select still sitting on a disabled or "Select…" option shows (nothing selected; shows "Select") instead of looking chosen. A field the page has flagged carries invalid, and validation messages inside cross-origin frames (Stripe and other payment widgets) are listed as alert lines like the page's own.


Next steps

Once you understand the page, take those refs and text and do something with them.