Core Usage
Finding Elements
Most of the time the @ref you get from snapshot is all you need. But sometimes a ref
goes stale, the target is buried in a hidden state, or you simply don't want to snapshot first.
This page covers the other ways to lock onto a target — the find semantic locators, raw CSS, coordinate clicks — plus the ladder that
escalates to eval when structured locating runs out.
When not to use @ref
@ref is the fastest path, but it is built on top of each snapshot and expires the moment the page changes.
In the situations below, reaching straight for a semantic locator or CSS is less work:
- The page is simple, and running a separate snapshot just to locate one button isn't worth it;
- refs keep going stale (after navigation, form submission, or a dynamic re-render);
- you already know the element's role, visible text, label, or a stable selector.
find semantic locators
find locates elements by semantics instead of a ref: role + name, visible text, form
label, placeholder, data-testid, or "first / Nth" match. On a hit, chain an action verb directly
(click / fill / type / hover …).
find label matches more than <label> elements — it also matches
aria-label and aria-labelledby, so icon buttons and custom controls
labeled only via ARIA can be found too.
If you do not know the locator kind yet, pass a natural-language description directly.
chrome-use ranks candidates by name, text, ancestor context, and role, includes cursor and
compact selector anchors, and never acts automatically.
$ chrome-use find role button click --name "Submit"
$ chrome-use find "edit web service settings button" # ranked candidates only
$ chrome-use find query "edit settings button" # explicit query syntax
$ 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 label "Close" click # hits an icon button with only aria-label="Close"
$ chrome-use find placeholder "Search" type "query"
$ chrome-use find testid "submit-btn" click
$ chrome-use find first ".card" click
$ chrome-use find nth 2 ".card" hover
收藏, not 保存,
so find text "保存" finds nothing, while snapshot -i steadily shows
button "收藏" [ref=eN] — just click @eN and you're done. Before concluding "the element doesn't exist," confirm its exact label.
Raw CSS selectors
Any action verb can take a CSS selector directly, no find required:
$ chrome-use click "#submit"
$ chrome-use fill "input[name=email]" "user@test.com"
$ chrome-use click "button.primary"
$ chrome-use click "//button[@type='submit']" # starts with //, /, (, ./ or .. = XPath, no xpath= prefix needed
//button[text()='Save'] never matches when the text is split across nodes (React's
{a} - {b}) or nested in a child element. Use contains(normalize-space(.), '…'), or
find "<label>" / text=<label> / snapshot -i + @ref.
When an XPath containing text() matches nothing, the error explains this gotcha, and
"Element not found" now keeps the selector and the resolver's specific diagnosis instead of always blaming a
closed shadow root / cross-origin iframe.
The escalation ladder
Locating an element follows a ladder from cheap to all-purpose. Walk down it in order, and don't get stuck grinding on one rung:
Fastest on cleanly structured pages. Grab the ref and click @eN.
When you'd rather not snapshot first, hit the target by semantics directly.
When you already have a stable selector, pass it straight to an action verb.
The moment any rung above fights back (stale ref, hidden state, an occluded click), drop straight to eval and operate the DOM directly.
eval
against the DOM; it's the fastest way to find out "why it failed." See Extracting Data for more.
click's auto-scroll and DOM fallback
click first scrolls the element into the viewport; if a coordinate click is occluded, it automatically falls back to the DOM's
.click(). If a click reports success but nothing happens — the classic being an autocomplete / menu
<li> that closes the instant it loses focus — retry that one click in DOM click mode, or just eval:
# retry this click in DOM click mode
$ AGENT_BROWSER_CLICK_MODE=dom chrome-use click @e3
# or select and click the item directly with JS
$ chrome-use eval "document.querySelector('#stubborn').click()"
Clicking by coordinates
When the only handle you have is a coordinate — a canvas, a marker from a screenshot, a target with no stable selector — click the pixel point directly:
$ chrome-use click 449 320 # click viewport coords (x y)
$ chrome-use click 449,320 # same, comma form
$ chrome-use click --coords 449,320 # same, explicit flag
Where find can't reach
Both find and CSS selectors are based on the page DOM (querySelectorAll), so they report
"Element not found" for two kinds of elements — even though snapshot -i plainly lists them (snapshots go through the CDP accessibility tree, which pierces both), and
get text can read them too:
- elements inside a closed shadow root;
- elements inside a cross-origin iframe.
@ref from snapshot
rather than find. When you need a coordinate fallback, box @ref gives the element's coordinate box.
See the notes on cross-origin iframes in Interacting.
Next steps
snapshot gives a structured @ref view.
click, fill, type drive a real browser.
eval and --schema scrape the page into clean JSON.
Semantic find role/text/label/placeholder/alt/title/testid requires exactly one visible match, including locate-only queries. Ambiguity returns up to eight candidates with visible state and selector/context hints; no action is dispatched and input values are omitted. Narrow --name/--exact, or use --within <CSS|@ref> to restrict the query to exactly one container. A scope must belong to the active tab's main document; cross-frame refs and an explicitly selected iframe are refused; use direct frame refs or `frame main`. find first/last/nth explicitly selects an order and keeps its existing behavior. A plain CSS selector or XPath given to an action (click, fill, type, hover, check, select, drag …) must match exactly one element too: one that matches several is refused with code selector_ambiguous, listing the first five matches with their text and position, and nothing is done. Narrow it, use a @ref, or choose by index with find nth <index> <selector> <action>; AGENT_BROWSER_STRICT_SELECTORS=0 (read when the session's daemon starts) restores first-match for old scripts. Roles and label names use Chrome accessibility data, including aria-labelledby; a semantic query re-resolves on each call. A detached target before dispatch fails safely; uncertain actions are never replayed.
Discover a scope from the page first: find query "Beta account" returns candidate selector anchors; choose the article/container corresponding to that heading, then use find role button click --name Save --exact --within "<returned-selector>". Inspect an ambiguous scope with snapshot -s "<selector>" and narrow it rather than accepting the first container. Unknown semantic-find options and duplicate --within are refused; use find label Email fill -- --name to enter literal flag-looking text. --exact false requests substring matching.
The existing chrome_use_find tool in mcp --tools all accepts within with the same unique-scope rules; tool count is unchanged. text for fill/type is passed literally, including --name --observe, rather than parsed as CLI options.
Semantic find retains the existing --observe unsupported warning; use one batch containing the scoped find action and a task-specific get text receipt when both are known. The MCP find tool does not advertise an observe field.