Skip to content

Locator

The locator finds a page element again after the page has changed. It lives in packages/locator and uses only the DOM, no extension API.

What is stored

A Locator holds frame (a list of iframe selectors), shadowPath (a list of shadow host selectors), an ordered list of strategies, and a fingerprint. See the content schema reference for every field.

  • Strategies, tried in stored order. Kinds: testid, id, aria, label, text, css, xpath.
  • Fingerprint: tag, role, short element text (up to 80 characters), up to 8 attributes, up to three ancestor headings, the sibling index and a rectangle with the viewport size. Form field values and select options are left out.

Resolution order

flowchart TB
  a["walkToRoot<br/>frames, then shadow"] -->|"fail"| f["Failure reason"]
  a --> b["Try each strategy<br/>in stored order"]
  b -->|"one visible match,<br/>score ok"| ok["Hit"]
  b -->|"none accepted"| c["Fuzzy search<br/>nearest scope"]
  c -->|"no result"| d["Fuzzy search<br/>whole root"]
  c --> ok2["Fuzzy hit"]
  d --> ok2
  d -->|"none"| f
  style ok fill:#e6f4ea,stroke:#1e7e34
  style ok2 fill:#e6f4ea,stroke:#1e7e34
  style f fill:#fde8e8,stroke:#b42318
Node Meaning
walkToRoot Follows frame into iframes, then shadowPath through open shadow roots. Can fail with a reason below
Try each strategy A strategy counts only when it finds exactly one visible element. The candidate is then scored against the stored fingerprint
Fuzzy search Scores every visible element with the same tag or role. Run first inside the closest unique ancestor taken from the css strategy, then over the whole root
Failure reason See the table below

Scoring and thresholds

Fingerprint weights: tag and role 0.2, text 0.3, ancestors 0.2, attributes 0.15, position 0.15.

Constant Value Use
HIT_THRESHOLD 0.6 Minimum score for a non-positional strategy to be accepted
FUZZY_THRESHOLD 0.75 Minimum score for a fuzzy match. Also the bar for xpath hits, because a positional path matches whatever now sits there
FUZZY_MARGIN 0.15 The best fuzzy candidate must beat the runner-up by this much, otherwise the result is ambiguous

An xpath hit is also rejected when every stored ancestor heading has changed.

Failure reasons

Reason Cause
not-found Nothing matched
low-confidence Something matched, below the bar
ambiguous Two fuzzy candidates scored within the margin
cross-origin-frame A frame in the path has no readable document. The player uses the frame agent instead. Not retried
frame-not-found The selector in frame matched no iframe
shadow-host-not-found A host selector in shadowPath matched nothing
shadow-root-closed The shadow root is closed and cannot be entered

resolveLocator can wait. With waitMs set it re-checks after DOM mutations (debounced 50 ms) and on a poll (250 ms by default) until the deadline.

Gotchas

  • Repeated elements with no distinguishing label (a row of identical icon buttons) score close to each other and resolve as ambiguous. Anchor on something with a distinguishing label or ancestor heading.
  • Visibility is part of matching. A target hidden by a scroll container or sticky header is treated as not renderable.
  • Weights and thresholds are constants in the code, not settings.