Skip to main content

Overview

Snapshot refs provide deterministic element selection for AI agents and automation scripts. Instead of writing brittle CSS selectors or XPath queries, you:
  1. Get an accessibility tree snapshot with numbered refs (@e1, @e2, etc.)
  2. Use those refs to interact with elements
  3. Get a new snapshot when the page changes
This workflow is optimal for AI agents because it separates perception (snapshot) from action (click/fill/etc.).

The Problem with Traditional Selectors

Traditional selectors have issues for automation:
Refs solve these problems by giving each element a unique, stable identifier within a snapshot.

How Refs Work

1. Get a Snapshot

The snapshot shows:
  • ARIA roles (heading, link, button, textbox, etc.)
  • Accessible names (the text shown to screen readers)
  • Refs (@e1, @e2) for interactive or named elements
  • Attributes (level, checked, etc.)

2. Interact Using Refs

Refs point to the exact element from the snapshot, so there’s no ambiguity.

3. Get a New Snapshot After Changes

When the page changes (navigation, dynamic content), get a fresh snapshot:
Refs are scoped to a single snapshot. After navigation or DOM changes, you need a new snapshot with new refs.

Accessibility Tree Source

Snapshots are built from the browser’s accessibility tree - the same structure used by screen readers:
Playwright’s ariaSnapshot() returns a text representation like:
This is then enhanced with refs and filtered based on options.

Ref Assignment Rules

Interactive Elements (Always Get Refs)

Elements with interactive ARIA roles automatically get refs:
Example:

Content Elements (Get Refs If Named)

Elements that provide context get refs only if they have a name:
Example:

Cursor-Interactive Elements (With -C Flag)

The --cursor flag finds elements that don’t have proper ARIA roles but are visually interactive:
This finds elements with:
  • cursor: pointer CSS property
  • onclick event handlers
  • tabindex attribute (except -1)
These get pseudo-roles:
This is useful for modern web apps that use <div> and <span> as buttons instead of semantic HTML.

Ref Storage Format

Refs are stored in a map that tracks how to locate each element:
Example:

Duplicate Handling

When multiple elements have the same role and name, refs include an nth index:
The nth field tells Playwright which instance to select:

Snapshot Filtering Options

Interactive Only (-i)

Show only interactive elements (buttons, links, inputs):
This is the recommended mode for AI agents - it reduces noise by hiding structural elements.

Cursor-Interactive (-C)

Include elements with cursor:pointer or click handlers:
Use this when targeting apps with custom clickable <div> elements.

Compact (-c)

Remove empty structural elements:
Structural roles (generic, group, list) without content are hidden:

Depth Limit (-d N)

Limit tree depth to N levels:
Useful for large pages where you only need top-level structure.

Scoped Snapshots (-s SELECTOR)

Limit snapshot to a CSS selector:
Only elements inside #main appear in the snapshot.

Using Refs in Commands

Refs work anywhere a selector is expected:
Refs are parsed in three formats:
  • @e1 - Recommended format
  • ref=e1 - Alternative format
  • e1 - Bare format (if it matches /^e\d+$/)

Ref Lifecycle

Creation

Refs are generated sequentially (e1, e2, e3, …) during snapshot generation:

Validity

Refs are valid until:
  • The page navigates to a new URL
  • The DOM changes significantly
  • You explicitly get a new snapshot
Using a stale ref won’t crash - Playwright will retry the locator - but it may fail or select the wrong element if the page changed.

Best Practice

Get a fresh snapshot after:
  • Navigation (agent-browser open ...)
  • Clicking links/buttons that change the page
  • Waiting for dynamic content to load

Annotated Screenshots

Visual representation of refs with numbered labels:
The screenshot has numbered labels [1], [2], [3] overlaid on each element. The label numbers match the ref numbers (@e1[1]). This is useful for:
  • Multimodal AI models that reason about visual layout
  • Debugging selector issues
  • Documenting UI flows

JSON Mode

Get snapshots in machine-readable format:
AI agents can parse this JSON to extract the snapshot tree and ref mappings.

Performance Characteristics

Snapshot generation is fast:
  • Small page (10-20 elements): ~50-100ms
  • Medium page (100-200 elements): ~200-400ms
  • Large page (500+ elements): ~500-1000ms
Interactive-only mode (-i) is faster because it filters earlier in the pipeline:

Comparison to Traditional Selectors

Next Steps

  • Architecture - Understand the Rust CLI + Node.js daemon design
  • Sessions - Learn about session isolation and persistence
  • Selectors - Master all selector types (CSS, refs, semantic)