> ## Documentation Index
> Fetch the complete documentation index at: https://webscrape.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get run

Poll a SmartBrowse run. Returns the run state, page and item counts so far, and — once the run is done — the extracted result.

**Cost:** Free. Polling never bills.

## Polling pattern

<CodeGroup>
  ```python Python theme={null}
  import requests, time

  API = "https://api.webscrape.ai/v1"
  HDR = {"X-API-Key": "wsg_live_..."}

  def run_and_wait(recipe_id):
      env = requests.post(f"{API}/smartbrowse/recipes/{recipe_id}/run", headers=HDR).json()
      run_id = env["data"]["run_id"]

      while True:
          env = requests.get(f"{API}/smartbrowse/runs/{run_id}", headers=HDR).json()
          run = env["data"]
          print(run["run_status"], run["pages_extracted"], "pages")
          if run["run_status"] in ("completed", "failed"):
              return run
          time.sleep(2)
  ```

  ```js Node theme={null}
  const API = "https://api.webscrape.ai/v1";
  const HDR = { "X-API-Key": "wsg_live_..." };

  async function runAndWait(recipeId) {
    const dispatched = await fetch(`${API}/smartbrowse/recipes/${recipeId}/run`, {
      method: "POST",
      headers: HDR,
    }).then(r => r.json());

    const id = dispatched.data.run_id;
    while (true) {
      const env = await fetch(`${API}/smartbrowse/runs/${id}`, { headers: HDR }).then(r => r.json());
      const run = env.data;
      if (run.run_status === "completed" || run.run_status === "failed") return run;
      await new Promise(r => setTimeout(r, 2000));
    }
  }
  ```
</CodeGroup>

## Result shape

When `data.run_status === "completed"`, the extracted items are at `data.result.pages[].items`. Each `items` entry matches the recipe's saved schema.

<Accordion title="Example response (completed)">
  ```json theme={null}
  {
    "status": "completed",
    "data": {
      "id": "k7Xb9dRmQ2p",
      "recipe_id": "m3Yc2tFvN8q",
      "run_status": "completed",
      "pages_extracted": 3,
      "items_extracted": 87,
      "credits_used": 6,
      "result": {
        "pages": [
          {
            "items": [
              { "name": "Product A", "price": "$19.99" },
              { "name": "Product B", "price": "$29.99" }
            ]
          }
        ],
        "mode": "replay",
        "drift": 0.02,
        "warnings": []
      },
      "started_at": "2026-05-21T12:00:00Z",
      "completed_at": "2026-05-21T12:01:30Z",
      "created_at": "2026-05-21T12:00:00Z"
    },
    "credits_used": 0,
    "credits_remaining": 494,
    "request_id": "req_aB3xY9Kp"
  }
  ```
</Accordion>

<Note>
  `data.credits_used` is the **run's total credits** (per-page accrual). The envelope's outer `credits_used` is always 0 — polling itself is free.
</Note>

## Tips

* `data.result.drift` (a number between 0 and 1) measures how much the page has changed since the recipe was authored. There's no fixed "too high" cutoff — read it alongside `data.items_extracted` when deciding whether to re-author. See the [SmartBrowse feature page](/docs/features/smartbrowse#drift-score).
* `data.result.warnings` lists non-fatal issues (e.g. pagination stalled before reaching the configured limit).
* For push delivery instead of polling, set up a webhook on the recipe from the dashboard.


## OpenAPI

````yaml GET /smartbrowse/runs/{id}
openapi: 3.1.0
info:
  title: webscrape.ai API
  version: '1.0'
  description: |
    The public webscrape.ai API. Fetch pages and get back structured JSON,
    HTML, markdown, or replayed browser output.

    Every response is wrapped in one of three envelope shapes —
    `completed`, `queued`, or `error`. Always check the top-level
    `status` first, then read `data` (success or queued) or `error`
    (failure).
  contact:
    name: webscrape.ai support
    email: hello@webscrape.ai
    url: https://webscrape.ai
servers:
  - url: https://api.webscrape.ai/v1
    description: Production
security:
  - ApiKeyAuth: []
tags:
  - name: Scrape
    description: Raw fetching and structured extraction.
  - name: SmartBrowse
    description: Real-Chrome recipe replay with pagination and interactions.
paths:
  /smartbrowse/runs/{id}:
    get:
      tags:
        - SmartBrowse
      summary: Poll a SmartBrowse run
      operationId: getSmartBrowseRun
      parameters:
        - name: id
          in: path
          required: true
          description: Opaque run ID (~11 base62 chars).
          schema:
            type: string
            example: k7Xb9dRmQ2p
      responses:
        '200':
          description: Run state returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SmartBrowseRunSuccess'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    SmartBrowseRunSuccess:
      allOf:
        - $ref: '#/components/schemas/EnvelopeBase'
        - type: object
          required:
            - data
            - credits_used
            - credits_remaining
          properties:
            status:
              type: string
              enum:
                - completed
            data:
              $ref: '#/components/schemas/SmartBrowseRunData'
            credits_used:
              type: integer
              description: >-
                Always 0. Polling is free; the run's accrued credits are
                surfaced in `data.credits_used`.
              example: 0
            credits_remaining:
              type: integer
    EnvelopeBase:
      type: object
      required:
        - status
        - request_id
      properties:
        status:
          type: string
          enum:
            - completed
            - queued
            - error
          description: Discriminator for the envelope variant.
        request_id:
          type: string
          example: req_aB3xY9Kp
          description: |
            Per-request id. Also returned as the `X-Request-ID` response
            header. Include it when reporting issues.
    SmartBrowseRunData:
      type: object
      required:
        - id
        - recipe_id
        - run_status
        - pages_extracted
        - items_extracted
        - credits_used
        - created_at
      properties:
        id:
          type: string
          example: k7Xb9dRmQ2p
          description: Opaque run ID (~11 base62 chars).
        recipe_id:
          type: string
          example: m3Yc2tFvN8q
          description: Opaque recipe ID (~11 base62 chars).
        run_status:
          $ref: '#/components/schemas/SmartBrowseRunStatus'
        pages_extracted:
          type: integer
        items_extracted:
          type: integer
        credits_used:
          type: integer
        started_at:
          type:
            - string
            - 'null'
          format: date-time
        completed_at:
          type:
            - string
            - 'null'
          format: date-time
        error:
          type: string
          description: Set only on `failed` / `cancelled` runs. Omitted otherwise.
        result:
          type: object
          description: Present once `run_status` is `completed`. Omitted while running.
          properties:
            pages:
              type: array
              items:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
            mode:
              type: string
            drift:
              type: number
            warnings:
              type: array
              items:
                type: string
        created_at:
          type: string
          format: date-time
    EnvelopeError:
      allOf:
        - $ref: '#/components/schemas/EnvelopeBase'
        - type: object
          required:
            - error
          properties:
            status:
              type: string
              enum:
                - error
            error:
              type: object
              required:
                - code
                - message
              properties:
                code:
                  $ref: '#/components/schemas/ErrorCode'
                message:
                  type: string
                  description: >-
                    Human-readable. May change between releases. Log it; don't
                    pattern-match.
                details:
                  description: >-
                    Optional structured context (e.g. `{balance, required}` for
                    `insufficient_credits`).
    SmartBrowseRunStatus:
      type: string
      enum:
        - queued
        - running
        - completed
        - failed
        - cancelled
      description: |
        Run lifecycle state. Renamed from `status` to avoid colliding
        with the envelope's outer `status`. `cancelled` appears when the
        run was force-stopped (e.g. account deletion confirmed while a
        run was in flight); `failed` covers everything else terminal.
    ErrorCode:
      type: string
      description: Stable error code. SDKs branch on this.
      enum:
        - invalid_request
        - unauthorized
        - insufficient_credits
        - email_verification_required
        - forbidden
        - not_found
        - conflict
        - account_deletion_pending
        - validation_failed
        - rate_limited
        - internal_error
        - service_unavailable
  responses:
    Unauthorized:
      description: Missing, invalid, or revoked API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: unauthorized
              message: missing or invalid credentials
            request_id: req_aB3xY9Kp
    NotFound:
      description: Resource does not exist or belongs to another user.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: not_found
              message: recipe not found
            request_id: req_aB3xY9Kp
    InternalError:
      description: Internal server error. Safe to retry with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: internal_error
              message: internal error
            request_id: req_aB3xY9Kp
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Generate from the [dashboard](https://webscrape.ai/app/api-keys).
        Format: `wsg_live_<32 base62 chars>`.

````