AlterLabAlterLab
PricingComparePlaygroundBlogDocsChangelog
    AlterLabAlterLab
    PricingComparePlaygroundBlogDocsChangelog
    IntroductionQuickstartInstallationYour First Request
    REST APICrawl APIMap APISearch APISERP APINewExtract APIAIJob PollingAPI KeysSessions APINewEnterprise APIEnterprise
    AccountAutoAlertsAutoAuthAutoBillingAutoCrawlAutoExtractAutoIntegrationsAutoKeysAutoMapAutoMonitorsAutoOrganizationsAutoSchedulesAutoScrapeAutoSearchAutoSessionsAutoUser WebhooksAutoV1 EndpointsAutoWebhooksAuto
    OverviewPythonNode.js
    JavaScript RenderingBrowser ActionsOutput FormatsPDF & OCRCachingWebhooksJSON Schema FilteringWebSocket Real-TimeBring Your Own ProxyProSticky SessionsProAuthenticated ScrapingNewHTTP Methods & BodiesNewStructured ExtractionAIWeb SearchSite MappingWeb CrawlingBatch ScrapingSchedulerChange DetectionCloud Storage ExportSpend LimitsOrganizations & TeamsAlerts & NotificationsExtraction ProfilesAIBYOK ExtractionAIOAuth2 Machine-to-MachineSupport & TicketsUnsupported Targets
    Structured ExtractionAIE-commerce ScrapingNews MonitoringPrice MonitoringMulti-Page CrawlingMonitoring DashboardAI Agent / MCPMCPAI Research AgentAISite CrawlingData Pipeline to Cloud
    E-commerceLead GenerationChange MonitoringRAG & AI PipelinesAIResearch
    PricingRate LimitsError CodesChangelogVersioning
    From FirecrawlFrom ApifyFrom ScrapingBee / ScraperAPIFrom Crawl4AIFrom SpiderFirecrawl v0 API ReferenceLegacy
    OverviewMCP ServerAIn8n NodeLangChainAICrewAIAILlamaIndexAISupabaseChrome ExtensionSoon
    PlaygroundPricingStatus

    Up to 5,000 free requests · No credit card

    Guide
    render_js

    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

    The response samples on this page show the shape of the data AlterLab returns. Values such as prices, URLs and counts are illustrative.

    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.

    NeedUse
    Wait until an element has renderedwait_for (request field, a CSS selector) — see Wait for Selector
    Trigger lazy-loaded images and sectionsadvanced.scroll_to_load with scroll_count
    Hide cookie bannersadvanced.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 stepsadvanced.actions

    Request Basics

    • Pass an ordered list in advanced.actions. Each item has a type and that type's fields.
    • Actions need a rendered page: advanced.render_js: true is 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.
    JSON
    {
      "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 typeFieldsDescription
    wait
    • milliseconds integer (100-30000)
      Fixed delay in ms; with selector, the visibility timeout
    • selector string, default 10000 ms timeout (max 500 chars; CSS, or XPath with // or xpath=)
      Element to wait for. Provide milliseconds, selector, or both
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Fixed delay, or wait until an element is visible. A selector wait that times out fails the action.
    wait_for
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      Element to wait for
    • state string, default visible (visible | hidden | attached | detached)
      hidden / detached wait for the element to disappear (e.g. a spinner)
    • timeout integer, default 10000 (1000-30000)
      Timeout in ms
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Wait for an element to reach a state. Fails on timeout.
    click
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      Element to click
    • timeout_ms integer, default 10000 (100-30000)
      Action timeout in ms
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Click an element.
    fill
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      Input element
    • value string, required (max 5000 chars)
      Value to type into the input
    • timeout_ms integer, default 10000 (100-30000)
      Action timeout in ms
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Fill an input field with a value.
    press
    • key string, required (max 50 chars)
      Key name, e.g. Enter, Tab, Escape, ArrowDown
    • selector string (max 500 chars; CSS, or XPath with // or xpath=)
      Element to focus first; omit to press on the page keyboard
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Press a keyboard key.
    scroll
    • direction string, default down (down | up)
      Scroll direction
    • amount integer, default 1 (1-20)
      Number of viewport heights
    Scroll by a number of viewport heights.
    infinite_scroll
    • max_scrolls integer, default 10 (1-50)
      Maximum scroll iterations
    • delay integer, default 1000 (200-5000)
      Delay between scrolls in ms
    • end_selector string (max 500 chars)
      Stop scrolling once this element exists
    Scroll repeatedly until the end of content or max_scrolls is reached.
    screenshot
    • full_page boolean, default true
      Full page, or the viewport only
    Capture a screenshot at this point in the sequence (returned as screenshot_url).
    evaluate
    • script string, required (max 5120 chars; blocked patterns rejected with 422)
      JavaScript expression or function body
    • timeout_ms integer, default 10000 (100-30000)
      Action timeout in ms
    Run JavaScript in the page. The return value is reported in result.
    dismiss_consent
    • mode string, default hide (hide | accept | reject)
      hide leaves consent state unchanged; accept / reject click the CMP button first
    Remove the cookie consent overlay from the live page.
    select
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      The <select> element
    • value string (max 500 chars)
      Option value attribute. Set exactly one of value or label
    • label string (max 500 chars)
      Option visible label. Set exactly one of value or label
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Choose an option in a <select> element.
    hover
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      Element to hover
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Hover over an element (menus, tooltips, lazy content).
    click_text
    • text string, required (max 500 chars)
      Visible text of the element to click
    • exact boolean, default false
      Whole-text, case-sensitive match; default is case-insensitive substring
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Click the element whose visible text matches.
    extract
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      Element to read
    • attribute string (max 100 chars)
      Attribute to return (e.g. href); omit to return the visible text
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Read text or an attribute from the first matching element into result.
    check
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      Checkbox or radio
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Check a checkbox or radio button.
    uncheck
    • selector string, required (max 500 chars; CSS, or XPath with // or xpath=)
      Checkbox
    • frame string | string[] (max 500 chars per selector; up to the supported nesting depth)
      Selector of the <iframe> holding the target; a list targets nested frames, outermost first
    Uncheck a checkbox.
    wait_event
    • event string, default load (load | domcontentloaded | networkidle)
      Load state to wait for
    • timeout integer, default 10000 (1000-30000)
      Timeout in ms
    Wait for a page load state (e.g. after a navigation).
    snapshot
    • format string, default html (html | markdown)
      Capture the rendered HTML or its markdown conversion
    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 evaluate script 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:

    1. Navigation and page load.
    2. scroll_to_load, when enabled.
    3. Your actions, in order. A screenshot action captures the page at that point in the sequence.
    4. Content extraction — the returned HTML, text, markdown and structured data reflect the page after your actions.
    5. The request-level advanced.screenshot, then advanced.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.

    FieldTypeDescription
    indexintegerPosition of the action in your actions array (0-based)
    typestringAction type that ran
    successbooleanWhether the action completed
    errorstring | nullError message when success is false (e.g. action_budget_exhausted)
    resultstring | nullReturn value of evaluate and extract actions
    screenshotstring | nullLegacy base64 screenshot; screenshot actions now use screenshot_url
    screenshot_urlstring | nullURL of the image captured by a screenshot action
    snapshot_urlstring | nullURL of the HTML or markdown captured by a snapshot action
    truncatedboolean | nullTrue when a snapshot was cut at the size cap
    duration_msinteger | nullWall time of the action in ms (0 when not run)
    JSON
    {
      "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 actions without render_js: true.
    • Action failure: the entry has success: false and an error message (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_executed instead 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 screenshot action that captures an image adds $0.0002, the same as advanced.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.

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

    Bash
    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

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

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

    Bash
    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" }
        ]
      }
    }'
    JavaScript RenderingOutput Formats
    Last updated: June 2026

    On this page