The `actions` array runs in order once the page has loaded. It works in **`mode: "browser"`

only

Available actions

- `wait` — fields `selector?`, `milliseconds?`. Waits for a selector to appear, or for a

fixed duration.

- `click` — field `selector`. Clicks the element.

- `scroll` — fields `direction?`, `amount?`, `selector?`. Defaults to down / 800 px and

scrolls smoothly in 10 steps 30 ms apart.

- `scrape` — field `selector?`. Takes an HTML snapshot at that moment; results come back

in `actions_result.scrapes[]`.

- `write` — fields `text`, `selector?`. Types text, into the focused element if no

selector is given.

- `press` — field `key`. Presses a keyboard key, such as `"Enter"` or `"Escape"`.

- `executeJavascript` — field `code`. Runs JavaScript; the return value arrives in

`actions_result.scripts_results[]`. The legacy `script` field is accepted and normalised

to `code`.

- `screenshot` — field `selector?`. Returns a base64 PNG in `actions_result.screenshots[]`.

The legacy `fullPage` field is accepted.

- `fill_form` — fields `fields` (each with `selector` and `value`) and `submit?`.

- `loop` — fields `maxIterations`, `actions`, `stopWhen?`. Repeats the inner action list.

Basic example

"actions": [
  { "type": "wait", "milliseconds": 1000 },
  { "type": "click", "selector": "#accept-cookies" },
  { "type": "scroll", "direction": "down", "amount": 800 },
  { "type": "wait", "selector": ".product-grid" }
]

Scrolling inside an element

With a `selector`, scrolling happens inside that element and the page itself stays put —

which is what infinite-scroll lists and scrollable dropdowns need.

{ "type": "scroll", "selector": "#results-list", "amount": 1000 }

If the selector matches no element, the action fails and so does the request.

Exhausting an infinite scroll

Use `loop` to repeat the scroll and take a snapshot on each pass.

{
  "type": "loop",
  "maxIterations": 10,
  "actions": [
    { "type": "scroll", "selector": "#results-list", "amount": 1200 },
    { "type": "wait", "milliseconds": 800 },
    { "type": "scrape", "selector": "#results-list" }
  ]
}

The snapshots arrive in order in `actions_result.scrapes[]`. This is the most practical way

to consume a paginating site.

Filling a form

{
  "type": "fill_form",
  "fields": [
    { "selector": "input[name=custname]", "value": "John Doe" },
    { "selector": "input[name=custemail]", "value": "john@example.com" },
    { "selector": "select#size", "value": "large" },
    { "selector": "input[name=topping][value=bacon]", "value": "true" },
    { "selector": "textarea[name=comments]", "value": "Ring the bell" }
  ],
  "submit": "button[type=submit]"
}

- Use `value: "true"` for checkboxes and radio buttons.

- With `submit`, that element is clicked and navigation is awaited.

- This is the correct way to submit an HTML form in browser mode; `options.method: "POST"`

is rejected there.

Running JavaScript

{ "type": "executeJavascript", "code": "return document.querySelectorAll('.item').length" }

Screenshots

{ "type": "screenshot", "selector": ".product-detail" }

Order matters. Dismiss overlays first, always put a `wait` after an interaction so the DOM

can update, call `scrape` only once the data is on screen, and raise

`options.timeout_seconds` as the action chain grows.

Last updated: September 21, 2026