> ## Documentation Index
> Fetch the complete documentation index at: https://docs.therefrain.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Selectors

> How runbook steps identify DOM elements using multi-strategy selectors.

## Overview

A **selector** tells the executor which DOM element to interact with. Selectors use multiple fields as fallback strategies — the executor tries each in priority order until a match is found.

## Selector fields

| Field            | Type                    | Priority | Description                                        |
| ---------------- | ----------------------- | :------: | -------------------------------------------------- |
| `id`             | string                  |     1    | Element `id` attribute (most reliable)             |
| `ariaLabel`      | string                  |     2    | `aria-label` attribute                             |
| `dataTestId`     | string                  |     3    | `data-testid` attribute                            |
| `dataAttributes` | Record\<string, string> |     4    | Other `data-*` attributes                          |
| `cssSelector`    | string                  |     5    | CSS selector                                       |
| `xPath`          | string                  |     6    | XPath expression                                   |
| `labelText`      | string                  |     7    | Associated `<label>` text                          |
| `innerText`      | string                  |     8    | Element inner text (max 200 chars)                 |
| `placeholder`    | string                  |     9    | `placeholder` attribute                            |
| `name`           | string                  |    10    | `name` attribute                                   |
| `rect`           | object                  |    11    | Position-based fallback (last resort)              |
| `tagName`        | string                  |     —    | HTML tag name (always present, used for filtering) |
| `role`           | string                  |     —    | ARIA `role` attribute                              |
| `inputType`      | string                  |     —    | `type` attribute of `<input>` elements             |

## Resolution pipeline

The executor resolves selectors through a 6-stage pipeline:

<Steps>
  <Step title="Deterministic resolution">
    Tries each selector field in priority order (id → ariaLabel → ... → name). No AI needed.
  </Step>

  <Step title="AI selector resolution">
    If deterministic resolution fails, AI analyzes the current page snapshot to find the target element.
  </Step>

  <Step title="Smart retry (3x)">
    Retries with increasing timeouts, waiting for DOM changes between attempts.
  </Step>

  <Step title="Scroll recovery">
    Scrolls the page to locate off-screen elements.
  </Step>

  <Step title="Agent Fallback">
    AI agent explores alternative paths to reach the target element. Requires Pro+ plan.
  </Step>

  <Step title="Vision Fallback">
    Takes a screenshot and uses vision AI to locate the element visually. Requires Pro+ plan.
  </Step>
</Steps>

## Example

```yaml theme={null}
action:
  type: click
  selector:
    tagName: button
    id: "submit-btn"
    ariaLabel: "Submit form"
    innerText: "Submit"
    role: "button"
```

In this example, the executor will:

1. Try `#submit-btn` first
2. Fall back to `[aria-label="Submit form"]` if the id is not found
3. Fall back to matching `innerText` if aria-label fails
4. Use `role` and `tagName` as additional filters throughout

## `rect` (position fallback)

Used as a last-resort deterministic strategy. Coordinates are relative to the viewport.

```yaml theme={null}
selector:
  tagName: button
  rect:
    x: 150
    y: 300
    width: 120
    height: 40
```

| Field    | Type   | Description    |
| -------- | ------ | -------------- |
| `x`      | number | X coordinate   |
| `y`      | number | Y coordinate   |
| `width`  | number | Element width  |
| `height` | number | Element height |

<Note>
  Position-based selectors are fragile — they break when the layout changes. Prefer semantic selectors (`id`, `ariaLabel`, `dataTestId`) whenever possible.
</Note>

## `dataAttributes`

Match elements by custom `data-*` attributes:

```yaml theme={null}
selector:
  tagName: div
  dataAttributes:
    row-id: "42"
    status: "active"
```

This matches `<div data-row-id="42" data-status="active">`.

## Best practices

1. **Prefer stable identifiers** — `id`, `dataTestId`, and `ariaLabel` survive UI redesigns better than CSS selectors or XPath.
2. **Avoid `rect`** — Position selectors break on any layout change. Only use them when no semantic selector exists.
3. **Keep `innerText` short** — Long text matches are brittle. The field is capped at 200 characters.
4. **Enable selector cache** — For repeated executions, `--enable-selector-cache` persists successful resolutions across runs.
