Browser Actions
Drive the page before AlterLab extracts it: click buttons, fill and submit forms, pick product variants, scroll feeds, run JavaScript and capture screenshots at any point — all inside one /api/v1/scrape request.
Example outputs
Actions vs Passive Options
Most rendered pages need no actions. Three passive options cover the common cases without scripting a sequence. Reach for actions when the content only appears after the page is interacted with. For worked use cases, see the Browser Actions API overview.
| Need | Use |
|---|---|
| Wait until an element has rendered | wait_for (request field, a CSS selector) — see Wait for Selector |
| Trigger lazy-loaded images and sections | advanced.scroll_to_load with scroll_count |
| Hide cookie banners | advanced.remove_cookie_banners (on by default) and advanced.consent |
| Click, type, select, hover, wait for a spinner to vanish, read a value mid-flow, screenshot between steps | advanced.actions |
Request Basics
- Pass an ordered list in
advanced.actions. Each item has atypeand that type's fields. - Actions need a rendered page:
advanced.render_js: trueis required, otherwise the request is rejected with 422. - At most 20 actions per request. They run sequentially, in the order you list them.
- A failed action is reported and skipped; the sequence continues with the next action.
{
"url": "https://example.com",
"advanced": {
"render_js": true,
"actions": [
{ "type": "click", "selector": "#show-all" },
{ "type": "wait_for", "selector": ".results", "state": "visible" }
]
}
}Action Reference
Selectors are CSS by default. Prefix with // or xpath= to use XPath.
| Action type | Fields | Description |
|---|---|---|
| wait |
| Fixed delay, or wait until an element is visible. A selector wait that times out fails the action. |
| wait_for |
| Wait for an element to reach a state. Fails on timeout. |
| click |
| Click an element. |
| fill |
| Fill an input field with a value. |
| press |
| Press a keyboard key. |
| scroll |
| Scroll by a number of viewport heights. |
| infinite_scroll |
| Scroll repeatedly until the end of content or max_scrolls is reached. |
| screenshot |
| Capture a screenshot at this point in the sequence (returned as screenshot_url). |
| evaluate |
| Run JavaScript in the page. The return value is reported in result. |
| dismiss_consent |
| Remove the cookie consent overlay from the live page. |
| select |
| Choose an option in a <select> element. |
| hover |
| Hover over an element (menus, tooltips, lazy content). |
| click_text |
| Click the element whose visible text matches. |
| extract |
| Read text or an attribute from the first matching element into result. |
| check |
| Check a checkbox or radio button. |
| uncheck |
| Uncheck a checkbox. |
| wait_event |
| Wait for a page load state (e.g. after a navigation). |
| snapshot |
| Capture the page HTML or markdown at this point (returned as snapshot_url). |
Limits
- Count: up to 20 actions per request.
- Selectors: up to 500 characters.
- Scripts: an
evaluatescript is at most 5120 characters. Scripts that use network or code-loading primitives are rejected with 422 before the job runs. Blocked: fetch, XMLHttpRequest, WebSocket, navigator.sendBeacon, importScripts, eval, Function constructor, dynamic import() / require(), __proto__ and prototype introspection, Reflect.get / Reflect.apply / Reflect.construct, String.fromCharCode, Proxy. - Time budget: the whole action sequence shares a 60 s cumulative budget. Actions that would start after it is spent are not run and report
action_budget_exhausted; the page is still extracted.
Ordering
Within one rendered request the steps run in this order:
- Navigation and page load.
scroll_to_load, when enabled.- Your
actions, in order. Ascreenshotaction captures the page at that point in the sequence. - Content extraction — the returned HTML, text, markdown and structured data reflect the page after your actions.
- The request-level
advanced.screenshot, thenadvanced.generate_pdf. Both capture the final state, after every action.
action_results
The response carries one entry per action in action_results, in the order the actions ran.
| Field | Type | Description |
|---|---|---|
| index | integer | Position of the action in your actions array (0-based) |
| type | string | Action type that ran |
| success | boolean | Whether the action completed |
| error | string | null | Error message when success is false (e.g. action_budget_exhausted) |
| result | string | null | Return value of evaluate and extract actions |
| screenshot | string | null | Legacy base64 screenshot; screenshot actions now use screenshot_url |
| screenshot_url | string | null | URL of the image captured by a screenshot action |
| snapshot_url | string | null | URL of the HTML or markdown captured by a snapshot action |
| truncated | boolean | null | True when a snapshot was cut at the size cap |
| duration_ms | integer | null | Wall time of the action in ms (0 when not run) |
{
"status_code": 200,
"action_results": [
{ "index": 0, "type": "select", "success": true, "error": null, "result": null, "screenshot_url": null },
{ "index": 1, "type": "extract", "success": true, "error": null, "result": "$129.00", "screenshot_url": null },
{ "index": 2, "type": "screenshot", "success": true, "error": null, "result": null,
"screenshot_url": "https://alterlab.io/downloads/screenshots/example.png" }
]
}Error Behaviour
- Validation (422): unknown action type, a missing required field, a value out of range, more than 20 actions, a blocked script pattern, or
actionswithoutrender_js: true. - Action failure: the entry has
success: falseand anerrormessage (for example a selector that never appeared). Later actions still run. - Budget exhausted: remaining actions report
action_budget_exhausted. - Actions not executed: if the scrape path could not run the actions at all, the job fails with
browser_actions_not_executedinstead of returning a 200 with empty results.
Pricing
- Actions run in the browser tier, $0.004 per request. There is no per-action fee.
- Each
screenshotaction that captures an image adds $0.0002, the same asadvanced.screenshot. Failed captures are free. - Other add-ons (PDF, extraction, OCR) are billed as usual — see Pricing.
Recipes
Hide a consent overlay before a screenshot
dismiss_consent in hide mode removes the overlay without accepting or rejecting anything.
curl -X POST https://api.alterlab.io/api/v1/scrape \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://news.example.com/article",
"advanced": {
"render_js": true,
"actions": [
{ "type": "dismiss_consent", "mode": "hide" },
{ "type": "screenshot", "full_page": true }
]
}
}'Load more and infinite scroll
Click a “Load more” button, wait for the new cards, then keep scrolling until the end marker appears.
curl -X POST https://api.alterlab.io/api/v1/scrape \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://shop.example.com/category/shoes",
"advanced": {
"render_js": true,
"actions": [
{ "type": "click", "selector": "button.load-more" },
{ "type": "wait_for", "selector": ".product-card:nth-child(48)", "timeout": 10000 },
{ "type": "infinite_scroll", "max_scrolls": 15, "delay": 1000, "end_selector": ".end-of-results" }
]
}
}'Select a product variant and extract the price
curl -X POST https://api.alterlab.io/api/v1/scrape \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://shop.example.com/product/runner-2",
"advanced": {
"render_js": true,
"actions": [
{ "type": "select", "selector": "select#size", "value": "42" },
{ "type": "click_text", "text": "Blue" },
{ "type": "wait_for", "selector": ".price[data-ready]", "state": "visible" },
{ "type": "extract", "selector": ".price" },
{ "type": "extract", "selector": "link[rel=canonical]", "attribute": "href" }
]
}
}'Fill and submit a search form
Press Enter in the input, or replace the press step with a click on the submit button.
curl -X POST https://api.alterlab.io/api/v1/scrape \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://books.example.com",
"advanced": {
"render_js": true,
"actions": [
{ "type": "fill", "selector": "input[name=q]", "value": "distributed systems" },
{ "type": "press", "key": "Enter", "selector": "input[name=q]" },
{ "type": "wait_event", "event": "domcontentloaded" },
{ "type": "wait_for", "selector": ".search-results .result", "timeout": 15000 }
]
}
}'Capture a screenshot mid-flow
Screenshot actions capture the page between steps — here before and after switching to yearly billing.
curl -X POST https://api.alterlab.io/api/v1/scrape \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/pricing",
"advanced": {
"render_js": true,
"actions": [
{ "type": "screenshot", "full_page": false },
{ "type": "click", "selector": "button[data-billing=yearly]" },
{ "type": "wait", "milliseconds": 500 },
{ "type": "screenshot", "full_page": false },
{ "type": "evaluate", "script": "document.querySelectorAll(\".plan\").length" }
]
}
}'