> ## 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.

# Loops & Branches

> Repeat steps with loops and execute conditionally with branches.

## Loops

A step with a `loop` definition repeats its nested `steps` multiple times. Two loop types are supported: `while` and `forEach`.

### `while` loop

Repeat while a condition is truthy:

```yaml theme={null}
steps:
  - ordinal: 0
    description: "Process pages until no next button"
    action:
      type: click
      selector:
        tagName: button
        innerText: "Next"
    url: "https://app.example.com/list"
    riskLevel: low
    requiresConfirmation: false
    loop:
      condition: "{{hasNextPage}}"
      maxIterations: 50
      counterVariable: pageIndex
    steps:
      - ordinal: 0
        description: "Extract data from current page"
        action:
          type: extract
          script: "document.querySelector('.data').textContent"
        url: "https://app.example.com/list"
        riskLevel: low
        requiresConfirmation: false
        captures:
          - name: hasNextPage
            strategy: evaluate
            expression: "!!document.querySelector('button:has-text(\"Next\")')"
```

### `forEach` loop

Iterate over items in a JSON array variable or a memory collection:

```yaml theme={null}
steps:
  - ordinal: 0
    description: "Process each user"
    action:
      type: navigate
      url: "https://app.example.com/users"
    url: "https://app.example.com/users"
    riskLevel: low
    requiresConfirmation: false
    loop:
      forEach: "{{userList}}"
      itemVariable: currentUser
      indexVariable: userIndex
      maxIterations: 100
    steps:
      - ordinal: 0
        description: "Navigate to user profile"
        action:
          type: navigate
          url: "https://app.example.com/users/{{currentUser}}"
        url: "https://app.example.com/users/{{currentUser}}"
        riskLevel: low
        requiresConfirmation: false
```

To iterate over a [memory collection](/yaml/memory-operations), use the `collection:` prefix:

```yaml theme={null}
loop:
  forEach: "collection:products"
  itemVariable: product
```

### Loop fields

| Field             | Type    | Required | Description                                          |
| ----------------- | ------- | :------: | ---------------------------------------------------- |
| `condition`       | string  |  One of  | Template expression for `while` loop                 |
| `forEach`         | string  |  One of  | Template variable (JSON array) or `collection:name`  |
| `itemVariable`    | string  |    No    | Variable name for the current item (`forEach` only)  |
| `indexVariable`   | string  |    No    | Variable name for the current index (`forEach` only) |
| `maxIterations`   | integer |    No    | Maximum number of iterations (safety limit)          |
| `counterVariable` | string  |    No    | Variable name for the loop counter                   |

<Note>
  A loop must have exactly one of `condition` or `forEach` — not both.
</Note>

## Branches

A step with `branches` executes different sets of steps based on a variable's value:

```yaml theme={null}
steps:
  - ordinal: 0
    description: "Branch based on account type"
    action:
      type: navigate
      url: "https://app.example.com/account"
    url: "https://app.example.com/account"
    riskLevel: low
    requiresConfirmation: false
    branches:
      value: "{{accountType}}"
      cases:
        - match: "personal"
          steps:
            - ordinal: 0
              description: "Fill personal form"
              action:
                type: input
                value: "{{name}}"
                selector:
                  tagName: input
                  name: "fullName"
              url: "https://app.example.com/account"
              riskLevel: low
              requiresConfirmation: false
        - match: "business"
          steps:
            - ordinal: 0
              description: "Fill business form"
              action:
                type: input
                value: "{{companyName}}"
                selector:
                  tagName: input
                  name: "company"
              url: "https://app.example.com/account"
              riskLevel: low
              requiresConfirmation: false
      default:
        steps:
          - ordinal: 0
            description: "Skip unrecognized type"
            action:
              type: wait
            url: "https://app.example.com/account"
            riskLevel: low
            requiresConfirmation: false
```

### Branch fields

| Field     | Type          | Required | Description                     |
| --------- | ------------- | :------: | ------------------------------- |
| `value`   | string        |    Yes   | Template expression to evaluate |
| `cases`   | BranchCase\[] |    Yes   | At least one case               |
| `default` | object        |    No    | Default case with `steps` array |

### BranchCase fields

| Field   | Type    | Required | Description                         |
| ------- | ------- | :------: | ----------------------------------- |
| `match` | string  |    Yes   | Value to match against              |
| `steps` | Step\[] |    Yes   | Steps to execute if matched (min 1) |

## Conditional steps

Any step can have a `condition` field. When the condition evaluates to a falsy value, the step is skipped:

```yaml theme={null}
steps:
  - ordinal: 0
    description: "Click confirm only if total > 0"
    condition: "{{totalAmount}}"
    action:
      type: click
      selector:
        tagName: button
        innerText: "Confirm"
    url: "https://app.example.com/checkout"
    riskLevel: medium
    requiresConfirmation: true
```

<Note>
  A step cannot have both `loop` and `branches` at the same time.
</Note>
