# paginate

The `paginate` step.

Runs `extract` on each page, then follows `next`. Top-level `many: true` fields are concatenated across pages and other fields come from the first page; it stops at `max_pages`, when `stop_when` holds, when `next` is not found, or when the step's `expect` does not hold after `next`. A page whose extraction fails fails the step on that page; a `next` that breaks after some pages keeps them, with a `pagination_incomplete` warning.

Type: `object`

## Keys

| Key | Type | Description |
|---|---|---|
| `paginate.delay_ms` | `integer` | The pause between pages in milliseconds, from `0` to `10000`. Defaults to `0`. |
| `paginate.extract` | `extract` | The extract schema applied on every page. It needs at least one top-level `many: true` field (lint `E010`). |
| `paginate.max_pages` | `integer` | The most pages to visit, from `1` to `1000`. Required (lint `E002`). |
| `paginate.next` | `target` | The target of the next-page link or button. |
| `paginate.stop_when` | `condition` | A condition checked on each page; pagination stops once it holds. |

Every step also takes the [common step keys](https://docs.kaab.ist/reference/dsl/steps#common-keys): `expect`, `id`, `if`, `name`, `on_error`, `optional`, `retry`, `side_effect`, `timeout_ms`, `x_kaab`.

## Example

```json
{
  "paginate": {
    "next": {
      "role": "link",
      "name": "Next"
    },
    "max_pages": 20,
    "stop_when": {
      "absent": {
        "role": "link",
        "name": "Next"
      }
    },
    "delay_ms": 250
  },
  "extract": {
    "products": {
      "selector": ".product-card",
      "many": true,
      "fields": {
        "name": ".title",
        "price": {
          "selector": ".price",
          "type": "money"
        }
      }
    }
  }
}
```

From the contract fixture `paginate-products`, a program the test suite validates.
