---
title: "Capture a page, inspect its DOM, and optionally automate it"
method: POST
path: "/screenshot"
tags: ["Capture"]
---

# Capture a page, inspect its DOM, and optionally automate it

`POST /screenshot`

## Request

- Base URL: `https://api.domscout.io`
- URL: `https://api.domscout.io/screenshot`
- Auth: API key in header `x-api-key`

Browser capture availability depends on your account capabilities and platform restrictions. Check GET /credits before starting browser work. A platform refusal returns HTTP 403 without upgrade_url: BROWSER_ISOLATION_REQUIRED when browser execution is unavailable, or BROWSER_EXECUTION_DENIED with reason public_capture_not_enabled when public capture is unavailable for your account. Upgrading or immediately retrying does not clear these refusals. Returns a direct result when it fits within the synchronous response budget; explicit async requests and rich results that exceed it return 202 with a durable job ID instead. Set responseType to json whenever semantic analysis, diagnostics, extraction, cleanup reporting, or action results are needed. A binary response is raw image/PDF bytes; binary delivery does not depend on the ordering of values in Accept.

## Headers

- `Idempotency-Key` string

## Request body

- union: Existing screenshot options are retained. New inspection, rendering, cleanup, diagnostics, extraction, retention, and action fields are additive.
  - object
    - `url` string, uri: Public HTTP(S) page URL. Unsafe addresses and redirects are rejected. Credentials in the authority (https://user:pass@host/) are refused with 400 — send authentication in the headers field instead, so it is never written to a capture log.
    - `html` string: Raw HTML to render instead of navigating to a URL.
    - `format` 'png' | 'jpeg' | 'webp' | 'pdf'
    - `responseType` 'json' | 'binary': How the capture comes back. "json" (default) returns a JSON envelope with base64 image data plus metadata and any analysis you requested. "binary" returns the raw file bytes with a matching Content-Type, and therefore has nowhere to carry metadata — so a binary request combined with an analysis option (cleanup, semanticSnapshot, diagnostics, or extract) is AUTO-PROMOTED to a durable job: it answers 202 with a jobId and metadata.autoPromotedAsync, and you poll GET /job/{jobId} for the result. A capture that fails after promotion reports its failure on the job rather than as a synchronous 4xx, carrying the same error code it would have returned inline. Binary responses also cannot carry metadata.ignoredFields.
    - `async` boolean: Force durable asynchronous execution. The service also auto-promotes captures expected to be large (rich JSON output) or slow (a URL capture stacking two or more whole-DOM passes, or one combined with fullPage/lazyScroll). Slow-capture promotion applies to Pro and above; Hobby keeps inline results.
    - `probe` boolean: Load and measure the page without a screenshot.
    - `width` integer
    - `height` integer
    - `isMobile` boolean
    - `hasTouch` boolean
    - `deviceScaleFactor` number
    - `quality` integer
    - `fullPage` boolean: Capture the whole scrollable page rather than the viewport. Adds a credit surcharge. The rendered page may be at most 12000px tall and 3840px wide; beyond that the request is refused with 400 and code CAPTURE_TOO_TALL or CAPTURE_TOO_WIDE rather than a truncated image. The same ceiling applies to captureSelector.
    - `selector` string, required: Legacy alias for captureSelector.
    - `captureSelector` string: The matched element must be visible within 5000ms, or the request is refused with 400 and code CAPTURE_SELECTOR_NOT_FOUND. It is also subject to the same 12000px ceiling as fullPage (400, CAPTURE_TOO_TALL).
    - `hideSelectors` string[]
    - `captureMode` 'default' | 'grid' | 'skeleton': default uses the requested viewport. grid produces responsive desktop, tablet, and mobile frames without reloading raw inline HTML. skeleton preserves a DOMContentLoaded frame before waiting for bounded hydration, so an inline HTML skeleton is still useful even if later network-idle settling times out. grid and skeleton also honour extractMarkdown; the Markdown is taken from the DOM after the mode has finished capturing, so for grid that is the final (desktop) viewport.
    - `waitForSelector` string: A wait that expires is a client-side outcome, not a server fault: the request is refused with 400 and code WAIT_FOR_SELECTOR_TIMEOUT.
    - `delay` integer
    - `headers` object: Scoped only to requests to the original target origin, including opened tabs and redirects. Sensitive header values do not appear in diagnostics or persisted artifacts.
    - `cookies` Cookie[]
      - `selector` string
      - `name` string, required
      - `value` string, required
      - `domain` string
      - `path` string
      - `httpOnly` boolean
      - `secure` boolean
      - `sameSite` 'Strict' | 'Lax' | 'None'
    - `injectCSS` string
    - `injectJS` string: Trusted-JavaScript feature. It requires an eligible plan, an operator-controlled account entitlement, and the platform-wide emergency switch.
    - `aiMode` boolean
    - `debugOverlay` boolean: Render console errors, page exceptions, failed requests and oversized assets into an overlay on the captured image. At most 200 entries are collected and each is truncated to 2048 characters; past that the overlay ends with a [TRUNCATED] marker. For structured, machine-readable output use `diagnostics` instead.
    - `performanceOverlay` boolean
    - `forceState` ForceState[]
      - `selector` string, required: A CSS selector. If it matches several elements the state is applied to the first, and the result says so.
      - `state` 'hover' | 'focus', required
    - `actions` Action[]
      - `action` 'click' | 'type' | 'scroll' | 'wait' | 'navigate' | 'back' | 'forward' | 'reload' | 'select' | 'check' | 'uncheck' | 'hover' | 'focus' | 'pressKey' | 'scrollIntoView' | 'waitForText' | 'waitForUrl' | 'waitForFunction' | 'waitForRequest' | 'waitForResponse' | 'waitForNetworkIdle' | 'openTab' | 'switchTab' | 'closeTab' | 'assert' | 'upload', required
      - `target` union: A selector-based action target. Semantic snapshot node IDs are inspection evidence only and are intentionally not accepted as durable action targets.
        - object
          - `css` string, required
        - object
          - `xpath` string, required
        - object
          - `text` union, required
            - string
            - object
              - …
        - object
          - `role` union, required
            - string
            - object
              - …
        - object
          - `label` string, required
        - object
          - `placeholder` string, required
        - object
          - `id` string, required
        - object
          - `name` string, required
        - object
          - `testId` string, required
          - `testIdAttribute` string
        - object
          - `coordinates` Coordinates, required
            - `x` number, required
            - `y` number, required
            - `space` 'viewport' | 'document' | 'screenshot'
      - `selector` string: Legacy CSS target. Do not combine with target.
      - `frame` union: A same-origin iframe target. Cross-origin frames are reported as metadata only.
        - object
          - `name` string, required
          - `urlIncludes` string
        - object
          - `name` string
          - `urlIncludes` string, required
      - `tabId` string: openTab: the id for the new tab, refused with 400 VALIDATION_FAILED if a tab with that id is open; omitted, a free tab-N id is generated. switchTab and closeTab: the tab to act on. closeTab refuses to close the last open tab, whatever its id (400 TAB_CLOSE_FORBIDDEN). New tabs inherit the resolved viewport, device scale and mobile/touch settings.
      - `url` string
      - `text` string
      - `exact` boolean
      - `key` string: Puppeteer key name, for example Enter, Tab, or Control+A.
      - `amount` number
      - `time` integer
      - `value` union
        - string
        - string[]
      - `expression` string: Trusted-JavaScript only; waitForFunction requires the same plan, account entitlement, and platform-wide emergency switch as injectJS.
      - `files` UploadFile[]
        - union
          - object
            - `base64` string, byte, required
            - `name` string, required
            - `mimeType` string
          - object
            - `s3Key` string, required: Withdrawn on 2026-07-30 and always rejected with 400. Browser uploads execute in the isolated renderer, which has no capture-bucket permission and no account identity to check ownership against. Send the file inline as base64 instead.
            - `name` string, required
      - `expected` string: Assertion expression: exists, visible, checked, unchecked, disabled, enabled, text:VALUE, or equals:VALUE.
      - `continueOnError` boolean
    - `typeSpeed` integer
    - `fastType` boolean
    - `captureTimeline` boolean
    - `extractMarkdown` boolean: Extract agent-readable Markdown. Empty main content falls back to the document body and then the accessibility tree when available.
    - `semanticNodes` boolean: Legacy interactive-node summary. Prefer semanticSnapshot for rich DOM data.
    - `simplifyDom` boolean
    - `lazyScroll` boolean
    - `pdfFormat` string: Paper size for a PDF capture. Matched case-insensitively against LETTER, LEGAL, TABLOID, LEDGER, A0, A1, A2, A3, A4, A5 and A6; anything else is refused with 400 and code PDF_FORMAT_UNSUPPORTED, which names the accepted values. An empty or omitted value takes the A4 default.
    - `landscape` boolean
    - `printBackground` boolean
    - `save` boolean: Persist capture artifacts using the configured finite, plan-bounded retention policy. JSON responses include metadata.captureId, metadata.retentionDays, and metadata.captureExpiresAt. A synchronous binary response exposes X-Domscout-Capture-Id and X-Domscout-Capture-Expires-At. Retrieve owned retained artifacts with GET /capture/{captureId}; that route has no separate S3-key field, but its signed downloadUrl can contain storage-path information and is a secret capability URL. Historic rows with expiresAt null are legacy permanent retention.
    - `captureName` string
    - `retentionDays` union: Plan-gated artifact retention selection. 365 is Enterprise-only. permanent is deprecated: it is still accepted but now resolves to the plan maximum rather than unlimited retention.
      - 7 | 30 | 90 | 365
      - 'permanent'
    - `callbackUrl` string, uri: Legacy per-job callback endpoint. Must be public HTTPS without URL credentials and must pass DNS/IP safety checks before acceptance and at every redirect hop.
    - `callbackSecret` string: Legacy per-job signing secret. It is never returned.
    - `semanticSnapshot` union
      - boolean: true enables the default rich snapshot.
      - object
        - `enabled` boolean
        - `maxNodes` integer
        - `detail` 'summary' | 'full'
        - `selectorBundles` boolean
        - `timing` 'beforeActions' | 'afterActions' | 'both'
        - `includeIframes` boolean
    - `diagnostics` union
      - boolean: true enables all bounded, redacted diagnostics.
      - object
        - `console` boolean
        - `pageErrors` boolean
        - `network` boolean
        - `resources` boolean
        - `timing` boolean
        - `maxEntries` integer
    - `render` RenderOptions
      - `disableAnimations` boolean
      - `colorScheme` 'light' | 'dark' | 'no-preference'
      - `locale` string: BCP 47 locale such as en-US.
      - `timezone` string: IANA timezone such as Asia/Kolkata.
      - `geolocation` Geolocation
        - `latitude` number, required
        - `longitude` number, required
        - `accuracy` number
      - `userAgent` string: Overrides the browser User-Agent string. The API enforces 1024 characters; a longer value is rejected with 400.
      - `transparentBackground` boolean
      - `blockResourceTypes` string[]
      - `blockDomains` string[]
      - `capturePadding` integer
      - `devicePreset` 'desktop' | 'iphone13' | 'pixel7' | 'ipad': Named viewport and device-emulation preset.
      - `reducedMotion` boolean
      - `media` 'screen' | 'print'
    - `cleanup` union
      - boolean: true enables all built-in heuristic cleanup categories.
      - object
        - `enabled` boolean
        - `preserveSelectors` string[]: Elements matching these selectors are never hidden by heuristic cleanup.
    - `extract` ExtractOptions
      - `fields` object, required
      - `strict` boolean: Fail the request when a required field is missing.
    - `renderJs` boolean: Set false to answer from one guarded HTTP GET instead of a browser. Roughly an order of magnitude faster and priced identically, but a page that renders its content with JavaScript returns whatever its server-side HTML says, which is frequently an empty shell. The response always reports metadata.renderJs and metadata.contentQuality so a caller can detect that case and retry with the browser. Refused with 400 VALIDATION_FAILED, naming each field and refunding the reservation, when combined with html, screenshot:true, a field that needs a live page (actions, injectJS, injectCSS, waitForSelector, selector, captureSelector, hideSelectors, forceState, cookies, headers, a non-zero delay, semanticNodes), save:true, or any option that carries a credit surcharge.
    - `fast` boolean: Alias for renderJs:false. Identical behaviour; both spellings are accepted.
    - `screenshot` boolean: POST /scrape only. Put the base64 image back in the response, which /scrape drops by default. Ignored by POST /screenshot, which always returns one. Requires a browser, so it cannot be combined with renderJs:false.
  - object
    - `url` string, uri, required: Public HTTP(S) page URL. Unsafe addresses and redirects are rejected. Credentials in the authority (https://user:pass@host/) are refused with 400 — send authentication in the headers field instead, so it is never written to a capture log.
    - `html` string: Raw HTML to render instead of navigating to a URL.
    - `format` 'png' | 'jpeg' | 'webp' | 'pdf'
    - `responseType` 'json' | 'binary': How the capture comes back. "json" (default) returns a JSON envelope with base64 image data plus metadata and any analysis you requested. "binary" returns the raw file bytes with a matching Content-Type, and therefore has nowhere to carry metadata — so a binary request combined with an analysis option (cleanup, semanticSnapshot, diagnostics, or extract) is AUTO-PROMOTED to a durable job: it answers 202 with a jobId and metadata.autoPromotedAsync, and you poll GET /job/{jobId} for the result. A capture that fails after promotion reports its failure on the job rather than as a synchronous 4xx, carrying the same error code it would have returned inline. Binary responses also cannot carry metadata.ignoredFields.
    - `async` boolean: Force durable asynchronous execution. The service also auto-promotes captures expected to be large (rich JSON output) or slow (a URL capture stacking two or more whole-DOM passes, or one combined with fullPage/lazyScroll). Slow-capture promotion applies to Pro and above; Hobby keeps inline results.
    - `probe` boolean: Load and measure the page without a screenshot.
    - `width` integer
    - `height` integer
    - `isMobile` boolean
    - `hasTouch` boolean
    - `deviceScaleFactor` number
    - `quality` integer
    - `fullPage` boolean: Capture the whole scrollable page rather than the viewport. Adds a credit surcharge. The rendered page may be at most 12000px tall and 3840px wide; beyond that the request is refused with 400 and code CAPTURE_TOO_TALL or CAPTURE_TOO_WIDE rather than a truncated image. The same ceiling applies to captureSelector.
    - `selector` string: Legacy alias for captureSelector.
    - `captureSelector` string: The matched element must be visible within 5000ms, or the request is refused with 400 and code CAPTURE_SELECTOR_NOT_FOUND. It is also subject to the same 12000px ceiling as fullPage (400, CAPTURE_TOO_TALL).
    - `hideSelectors` string[]
    - `captureMode` 'default' | 'grid' | 'skeleton': default uses the requested viewport. grid produces responsive desktop, tablet, and mobile frames without reloading raw inline HTML. skeleton preserves a DOMContentLoaded frame before waiting for bounded hydration, so an inline HTML skeleton is still useful even if later network-idle settling times out. grid and skeleton also honour extractMarkdown; the Markdown is taken from the DOM after the mode has finished capturing, so for grid that is the final (desktop) viewport.
    - `waitForSelector` string: A wait that expires is a client-side outcome, not a server fault: the request is refused with 400 and code WAIT_FOR_SELECTOR_TIMEOUT.
    - `delay` integer
    - `headers` object: Scoped only to requests to the original target origin, including opened tabs and redirects. Sensitive header values do not appear in diagnostics or persisted artifacts.
    - `cookies` Cookie[]
      - `selector` string
      - `name` string, required
      - `value` string, required
      - `domain` string
      - `path` string
      - `httpOnly` boolean
      - `secure` boolean
      - `sameSite` 'Strict' | 'Lax' | 'None'
    - `injectCSS` string
    - `injectJS` string: Trusted-JavaScript feature. It requires an eligible plan, an operator-controlled account entitlement, and the platform-wide emergency switch.
    - `aiMode` boolean
    - `debugOverlay` boolean: Render console errors, page exceptions, failed requests and oversized assets into an overlay on the captured image. At most 200 entries are collected and each is truncated to 2048 characters; past that the overlay ends with a [TRUNCATED] marker. For structured, machine-readable output use `diagnostics` instead.
    - `performanceOverlay` boolean
    - `forceState` ForceState[]
      - `selector` string, required: A CSS selector. If it matches several elements the state is applied to the first, and the result says so.
      - `state` 'hover' | 'focus', required
    - `actions` Action[]
      - `action` 'click' | 'type' | 'scroll' | 'wait' | 'navigate' | 'back' | 'forward' | 'reload' | 'select' | 'check' | 'uncheck' | 'hover' | 'focus' | 'pressKey' | 'scrollIntoView' | 'waitForText' | 'waitForUrl' | 'waitForFunction' | 'waitForRequest' | 'waitForResponse' | 'waitForNetworkIdle' | 'openTab' | 'switchTab' | 'closeTab' | 'assert' | 'upload', required
      - `target` union: A selector-based action target. Semantic snapshot node IDs are inspection evidence only and are intentionally not accepted as durable action targets.
        - object
          - `css` string, required
        - object
          - `xpath` string, required
        - object
          - `text` union, required
            - string
            - object
              - …
        - object
          - `role` union, required
            - string
            - object
              - …
        - object
          - `label` string, required
        - object
          - `placeholder` string, required
        - object
          - `id` string, required
        - object
          - `name` string, required
        - object
          - `testId` string, required
          - `testIdAttribute` string
        - object
          - `coordinates` Coordinates, required
            - `x` number, required
            - `y` number, required
            - `space` 'viewport' | 'document' | 'screenshot'
      - `selector` string: Legacy CSS target. Do not combine with target.
      - `frame` union: A same-origin iframe target. Cross-origin frames are reported as metadata only.
        - object
          - `name` string, required
          - `urlIncludes` string
        - object
          - `name` string
          - `urlIncludes` string, required
      - `tabId` string: openTab: the id for the new tab, refused with 400 VALIDATION_FAILED if a tab with that id is open; omitted, a free tab-N id is generated. switchTab and closeTab: the tab to act on. closeTab refuses to close the last open tab, whatever its id (400 TAB_CLOSE_FORBIDDEN). New tabs inherit the resolved viewport, device scale and mobile/touch settings.
      - `url` string
      - `text` string
      - `exact` boolean
      - `key` string: Puppeteer key name, for example Enter, Tab, or Control+A.
      - `amount` number
      - `time` integer
      - `value` union
        - string
        - string[]
      - `expression` string: Trusted-JavaScript only; waitForFunction requires the same plan, account entitlement, and platform-wide emergency switch as injectJS.
      - `files` UploadFile[]
        - union
          - object
            - `base64` string, byte, required
            - `name` string, required
            - `mimeType` string
          - object
            - `s3Key` string, required: Withdrawn on 2026-07-30 and always rejected with 400. Browser uploads execute in the isolated renderer, which has no capture-bucket permission and no account identity to check ownership against. Send the file inline as base64 instead.
            - `name` string, required
      - `expected` string: Assertion expression: exists, visible, checked, unchecked, disabled, enabled, text:VALUE, or equals:VALUE.
      - `continueOnError` boolean
    - `typeSpeed` integer
    - `fastType` boolean
    - `captureTimeline` boolean
    - `extractMarkdown` boolean: Extract agent-readable Markdown. Empty main content falls back to the document body and then the accessibility tree when available.
    - `semanticNodes` boolean: Legacy interactive-node summary. Prefer semanticSnapshot for rich DOM data.
    - `simplifyDom` boolean
    - `lazyScroll` boolean
    - `pdfFormat` string: Paper size for a PDF capture. Matched case-insensitively against LETTER, LEGAL, TABLOID, LEDGER, A0, A1, A2, A3, A4, A5 and A6; anything else is refused with 400 and code PDF_FORMAT_UNSUPPORTED, which names the accepted values. An empty or omitted value takes the A4 default.
    - `landscape` boolean
    - `printBackground` boolean
    - `save` boolean: Persist capture artifacts using the configured finite, plan-bounded retention policy. JSON responses include metadata.captureId, metadata.retentionDays, and metadata.captureExpiresAt. A synchronous binary response exposes X-Domscout-Capture-Id and X-Domscout-Capture-Expires-At. Retrieve owned retained artifacts with GET /capture/{captureId}; that route has no separate S3-key field, but its signed downloadUrl can contain storage-path information and is a secret capability URL. Historic rows with expiresAt null are legacy permanent retention.
    - `captureName` string
    - `retentionDays` union: Plan-gated artifact retention selection. 365 is Enterprise-only. permanent is deprecated: it is still accepted but now resolves to the plan maximum rather than unlimited retention.
      - 7 | 30 | 90 | 365
      - 'permanent'
    - `callbackUrl` string, uri: Legacy per-job callback endpoint. Must be public HTTPS without URL credentials and must pass DNS/IP safety checks before acceptance and at every redirect hop.
    - `callbackSecret` string: Legacy per-job signing secret. It is never returned.
    - `semanticSnapshot` union
      - boolean: true enables the default rich snapshot.
      - object
        - `enabled` boolean
        - `maxNodes` integer
        - `detail` 'summary' | 'full'
        - `selectorBundles` boolean
        - `timing` 'beforeActions' | 'afterActions' | 'both'
        - `includeIframes` boolean
    - `diagnostics` union
      - boolean: true enables all bounded, redacted diagnostics.
      - object
        - `console` boolean
        - `pageErrors` boolean
        - `network` boolean
        - `resources` boolean
        - `timing` boolean
        - `maxEntries` integer
    - `render` RenderOptions
      - `disableAnimations` boolean
      - `colorScheme` 'light' | 'dark' | 'no-preference'
      - `locale` string: BCP 47 locale such as en-US.
      - `timezone` string: IANA timezone such as Asia/Kolkata.
      - `geolocation` Geolocation
        - `latitude` number, required
        - `longitude` number, required
        - `accuracy` number
      - `userAgent` string: Overrides the browser User-Agent string. The API enforces 1024 characters; a longer value is rejected with 400.
      - `transparentBackground` boolean
      - `blockResourceTypes` string[]
      - `blockDomains` string[]
      - `capturePadding` integer
      - `devicePreset` 'desktop' | 'iphone13' | 'pixel7' | 'ipad': Named viewport and device-emulation preset.
      - `reducedMotion` boolean
      - `media` 'screen' | 'print'
    - `cleanup` union
      - boolean: true enables all built-in heuristic cleanup categories.
      - object
        - `enabled` boolean
        - `preserveSelectors` string[]: Elements matching these selectors are never hidden by heuristic cleanup.
    - `extract` ExtractOptions
      - `fields` object, required
      - `strict` boolean: Fail the request when a required field is missing.
    - `renderJs` boolean: Set false to answer from one guarded HTTP GET instead of a browser. Roughly an order of magnitude faster and priced identically, but a page that renders its content with JavaScript returns whatever its server-side HTML says, which is frequently an empty shell. The response always reports metadata.renderJs and metadata.contentQuality so a caller can detect that case and retry with the browser. Refused with 400 VALIDATION_FAILED, naming each field and refunding the reservation, when combined with html, screenshot:true, a field that needs a live page (actions, injectJS, injectCSS, waitForSelector, selector, captureSelector, hideSelectors, forceState, cookies, headers, a non-zero delay, semanticNodes), save:true, or any option that carries a credit surcharge.
    - `fast` boolean: Alias for renderJs:false. Identical behaviour; both spellings are accepted.
    - `screenshot` boolean: POST /scrape only. Put the base64 image back in the response, which /scrape drops by default. Ignored by POST /screenshot, which always returns one. Requires a browser, so it cannot be combined with renderJs:false.
  - object
    - `url` string, uri: Public HTTP(S) page URL. Unsafe addresses and redirects are rejected. Credentials in the authority (https://user:pass@host/) are refused with 400 — send authentication in the headers field instead, so it is never written to a capture log.
    - `html` string, required: Raw HTML to render instead of navigating to a URL.
    - `format` 'png' | 'jpeg' | 'webp' | 'pdf'
    - `responseType` 'json' | 'binary': How the capture comes back. "json" (default) returns a JSON envelope with base64 image data plus metadata and any analysis you requested. "binary" returns the raw file bytes with a matching Content-Type, and therefore has nowhere to carry metadata — so a binary request combined with an analysis option (cleanup, semanticSnapshot, diagnostics, or extract) is AUTO-PROMOTED to a durable job: it answers 202 with a jobId and metadata.autoPromotedAsync, and you poll GET /job/{jobId} for the result. A capture that fails after promotion reports its failure on the job rather than as a synchronous 4xx, carrying the same error code it would have returned inline. Binary responses also cannot carry metadata.ignoredFields.
    - `async` boolean: Force durable asynchronous execution. The service also auto-promotes captures expected to be large (rich JSON output) or slow (a URL capture stacking two or more whole-DOM passes, or one combined with fullPage/lazyScroll). Slow-capture promotion applies to Pro and above; Hobby keeps inline results.
    - `probe` boolean: Load and measure the page without a screenshot.
    - `width` integer
    - `height` integer
    - `isMobile` boolean
    - `hasTouch` boolean
    - `deviceScaleFactor` number
    - `quality` integer
    - `fullPage` boolean: Capture the whole scrollable page rather than the viewport. Adds a credit surcharge. The rendered page may be at most 12000px tall and 3840px wide; beyond that the request is refused with 400 and code CAPTURE_TOO_TALL or CAPTURE_TOO_WIDE rather than a truncated image. The same ceiling applies to captureSelector.
    - `selector` string: Legacy alias for captureSelector.
    - `captureSelector` string: The matched element must be visible within 5000ms, or the request is refused with 400 and code CAPTURE_SELECTOR_NOT_FOUND. It is also subject to the same 12000px ceiling as fullPage (400, CAPTURE_TOO_TALL).
    - `hideSelectors` string[]
    - `captureMode` 'default' | 'grid' | 'skeleton': default uses the requested viewport. grid produces responsive desktop, tablet, and mobile frames without reloading raw inline HTML. skeleton preserves a DOMContentLoaded frame before waiting for bounded hydration, so an inline HTML skeleton is still useful even if later network-idle settling times out. grid and skeleton also honour extractMarkdown; the Markdown is taken from the DOM after the mode has finished capturing, so for grid that is the final (desktop) viewport.
    - `waitForSelector` string: A wait that expires is a client-side outcome, not a server fault: the request is refused with 400 and code WAIT_FOR_SELECTOR_TIMEOUT.
    - `delay` integer
    - `headers` object: Scoped only to requests to the original target origin, including opened tabs and redirects. Sensitive header values do not appear in diagnostics or persisted artifacts.
    - `cookies` Cookie[]
      - `selector` string
      - `name` string, required
      - `value` string, required
      - `domain` string
      - `path` string
      - `httpOnly` boolean
      - `secure` boolean
      - `sameSite` 'Strict' | 'Lax' | 'None'
    - `injectCSS` string
    - `injectJS` string: Trusted-JavaScript feature. It requires an eligible plan, an operator-controlled account entitlement, and the platform-wide emergency switch.
    - `aiMode` boolean
    - `debugOverlay` boolean: Render console errors, page exceptions, failed requests and oversized assets into an overlay on the captured image. At most 200 entries are collected and each is truncated to 2048 characters; past that the overlay ends with a [TRUNCATED] marker. For structured, machine-readable output use `diagnostics` instead.
    - `performanceOverlay` boolean
    - `forceState` ForceState[]
      - `selector` string, required: A CSS selector. If it matches several elements the state is applied to the first, and the result says so.
      - `state` 'hover' | 'focus', required
    - `actions` Action[]
      - `action` 'click' | 'type' | 'scroll' | 'wait' | 'navigate' | 'back' | 'forward' | 'reload' | 'select' | 'check' | 'uncheck' | 'hover' | 'focus' | 'pressKey' | 'scrollIntoView' | 'waitForText' | 'waitForUrl' | 'waitForFunction' | 'waitForRequest' | 'waitForResponse' | 'waitForNetworkIdle' | 'openTab' | 'switchTab' | 'closeTab' | 'assert' | 'upload', required
      - `target` union: A selector-based action target. Semantic snapshot node IDs are inspection evidence only and are intentionally not accepted as durable action targets.
        - object
          - `css` string, required
        - object
          - `xpath` string, required
        - object
          - `text` union, required
            - string
            - object
              - …
        - object
          - `role` union, required
            - string
            - object
              - …
        - object
          - `label` string, required
        - object
          - `placeholder` string, required
        - object
          - `id` string, required
        - object
          - `name` string, required
        - object
          - `testId` string, required
          - `testIdAttribute` string
        - object
          - `coordinates` Coordinates, required
            - `x` number, required
            - `y` number, required
            - `space` 'viewport' | 'document' | 'screenshot'
      - `selector` string: Legacy CSS target. Do not combine with target.
      - `frame` union: A same-origin iframe target. Cross-origin frames are reported as metadata only.
        - object
          - `name` string, required
          - `urlIncludes` string
        - object
          - `name` string
          - `urlIncludes` string, required
      - `tabId` string: openTab: the id for the new tab, refused with 400 VALIDATION_FAILED if a tab with that id is open; omitted, a free tab-N id is generated. switchTab and closeTab: the tab to act on. closeTab refuses to close the last open tab, whatever its id (400 TAB_CLOSE_FORBIDDEN). New tabs inherit the resolved viewport, device scale and mobile/touch settings.
      - `url` string
      - `text` string
      - `exact` boolean
      - `key` string: Puppeteer key name, for example Enter, Tab, or Control+A.
      - `amount` number
      - `time` integer
      - `value` union
        - string
        - string[]
      - `expression` string: Trusted-JavaScript only; waitForFunction requires the same plan, account entitlement, and platform-wide emergency switch as injectJS.
      - `files` UploadFile[]
        - union
          - object
            - `base64` string, byte, required
            - `name` string, required
            - `mimeType` string
          - object
            - `s3Key` string, required: Withdrawn on 2026-07-30 and always rejected with 400. Browser uploads execute in the isolated renderer, which has no capture-bucket permission and no account identity to check ownership against. Send the file inline as base64 instead.
            - `name` string, required
      - `expected` string: Assertion expression: exists, visible, checked, unchecked, disabled, enabled, text:VALUE, or equals:VALUE.
      - `continueOnError` boolean
    - `typeSpeed` integer
    - `fastType` boolean
    - `captureTimeline` boolean
    - `extractMarkdown` boolean: Extract agent-readable Markdown. Empty main content falls back to the document body and then the accessibility tree when available.
    - `semanticNodes` boolean: Legacy interactive-node summary. Prefer semanticSnapshot for rich DOM data.
    - `simplifyDom` boolean
    - `lazyScroll` boolean
    - `pdfFormat` string: Paper size for a PDF capture. Matched case-insensitively against LETTER, LEGAL, TABLOID, LEDGER, A0, A1, A2, A3, A4, A5 and A6; anything else is refused with 400 and code PDF_FORMAT_UNSUPPORTED, which names the accepted values. An empty or omitted value takes the A4 default.
    - `landscape` boolean
    - `printBackground` boolean
    - `save` boolean: Persist capture artifacts using the configured finite, plan-bounded retention policy. JSON responses include metadata.captureId, metadata.retentionDays, and metadata.captureExpiresAt. A synchronous binary response exposes X-Domscout-Capture-Id and X-Domscout-Capture-Expires-At. Retrieve owned retained artifacts with GET /capture/{captureId}; that route has no separate S3-key field, but its signed downloadUrl can contain storage-path information and is a secret capability URL. Historic rows with expiresAt null are legacy permanent retention.
    - `captureName` string
    - `retentionDays` union: Plan-gated artifact retention selection. 365 is Enterprise-only. permanent is deprecated: it is still accepted but now resolves to the plan maximum rather than unlimited retention.
      - 7 | 30 | 90 | 365
      - 'permanent'
    - `callbackUrl` string, uri: Legacy per-job callback endpoint. Must be public HTTPS without URL credentials and must pass DNS/IP safety checks before acceptance and at every redirect hop.
    - `callbackSecret` string: Legacy per-job signing secret. It is never returned.
    - `semanticSnapshot` union
      - boolean: true enables the default rich snapshot.
      - object
        - `enabled` boolean
        - `maxNodes` integer
        - `detail` 'summary' | 'full'
        - `selectorBundles` boolean
        - `timing` 'beforeActions' | 'afterActions' | 'both'
        - `includeIframes` boolean
    - `diagnostics` union
      - boolean: true enables all bounded, redacted diagnostics.
      - object
        - `console` boolean
        - `pageErrors` boolean
        - `network` boolean
        - `resources` boolean
        - `timing` boolean
        - `maxEntries` integer
    - `render` RenderOptions
      - `disableAnimations` boolean
      - `colorScheme` 'light' | 'dark' | 'no-preference'
      - `locale` string: BCP 47 locale such as en-US.
      - `timezone` string: IANA timezone such as Asia/Kolkata.
      - `geolocation` Geolocation
        - `latitude` number, required
        - `longitude` number, required
        - `accuracy` number
      - `userAgent` string: Overrides the browser User-Agent string. The API enforces 1024 characters; a longer value is rejected with 400.
      - `transparentBackground` boolean
      - `blockResourceTypes` string[]
      - `blockDomains` string[]
      - `capturePadding` integer
      - `devicePreset` 'desktop' | 'iphone13' | 'pixel7' | 'ipad': Named viewport and device-emulation preset.
      - `reducedMotion` boolean
      - `media` 'screen' | 'print'
    - `cleanup` union
      - boolean: true enables all built-in heuristic cleanup categories.
      - object
        - `enabled` boolean
        - `preserveSelectors` string[]: Elements matching these selectors are never hidden by heuristic cleanup.
    - `extract` ExtractOptions
      - `fields` object, required
      - `strict` boolean: Fail the request when a required field is missing.
    - `renderJs` boolean: Set false to answer from one guarded HTTP GET instead of a browser. Roughly an order of magnitude faster and priced identically, but a page that renders its content with JavaScript returns whatever its server-side HTML says, which is frequently an empty shell. The response always reports metadata.renderJs and metadata.contentQuality so a caller can detect that case and retry with the browser. Refused with 400 VALIDATION_FAILED, naming each field and refunding the reservation, when combined with html, screenshot:true, a field that needs a live page (actions, injectJS, injectCSS, waitForSelector, selector, captureSelector, hideSelectors, forceState, cookies, headers, a non-zero delay, semanticNodes), save:true, or any option that carries a credit surcharge.
    - `fast` boolean: Alias for renderJs:false. Identical behaviour; both spellings are accepted.
    - `screenshot` boolean: POST /scrape only. Put the base64 image back in the response, which /scrape drops by default. Ignored by POST /screenshot, which always returns one. Requires a browser, so it cannot be combined with renderJs:false.

## Response `200`

Synchronous capture result.

- ScreenshotResponse
  - `status` 'success', required
  - `metadata` ScreenshotMetadata
    - `url` string, nullable
    - `format` string
    - `httpStatus` integer, nullable
    - `viewport` Viewport
      - `width` integer, required
      - `height` integer, required
      - `isMobile` boolean
      - `deviceScaleFactor` number
    - `durationMs` integer
    - `timing` object
      - `totalMs` integer
      - `navigationMs` integer
      - `actionMs` integer
    - `render` object: Applied render controls and any non-fatal render warnings.
    - `captureId` string, uuid
    - `saved` boolean
    - `retentionDays` 7 | 30 | 90 | 365: Effective retention selected for a successful save.
    - `captureExpiresAt` string, date-time: Effective expiry time for a successful saved capture.
    - `partialResult` boolean
    - `framesCompleted` integer
    - `actionsRemaining` integer
    - `budgetWarning` string: Present when the action budget was exhausted and remaining steps were skipped. The budget is 24s on the synchronous path and 52s for async, monitor, batch-child and crawl-child work, and the message states the one that applied.
    - `syncTip` string
    - `warning` string: Primary non-fatal capture warning. Values include network_idle_timeout, navigation_aborted_after_document_load, access_challenge, and hide_selector_invalid (a hideSelectors entry was not valid CSS and was skipped).
    - `warningDetail` string
    - `warnings` object[]: All non-fatal capture warnings in detection order. The scalar warning and warningDetail fields retain the primary warning for backward compatibility.
      - `code` string, required
      - `detail` string, required
    - `accessChallenge` object: Present when the rendered document strongly resembles a target-side access or anti-bot verification page. Detection is advisory and the artifact is still returned.
      - `detected` boolean, required
      - `provider` string, nullable
      - `signals` string[], required
    - `ignoredFields` string[]: Top-level request fields this API does not understand, echoed back so a misspelled option is visible. Unknown fields remain accepted and ignored so that existing requests stay valid — but an ignored option changes both what you receive and what you are charged, so it is named here. Absent when every field was recognised.
    - `forceState` ForceStateResult[]: One entry per forceState requested, reporting whether it was applied. Present only when forceState was sent. An identical-looking capture with applied:false and reason SELECTOR_NOT_MATCHED means the element was never found.
      - `selector` string
      - `state` string
      - `applied` boolean
      - `matched` integer: How many elements the selector matched. Present when applied.
      - `note` string: Present when the selector matched more than one element.
      - `reason` 'SELECTOR_NOT_MATCHED' | 'STATE_NOT_APPLIED': Why it was not applied. SELECTOR_NOT_MATCHED means the page has no such element.
      - `error` string: Redacted browser error, when one was raised.
    - `credits` CaptureCredits: What this request cost and what is left. Present on billable JSON responses only.
      - `cost` integer: Credits this request consumed.
      - `chargedTo` string: Which bucket paid.
      - `remaining` integer, nullable
      - `quotaRemaining` integer, nullable
      - `overage` boolean: True when the paying bucket was beyond the plan's included quota and therefore metered.
  - `screenshotBase64` string, byte
  - `pdfBase64` string, byte
  - `mobileBase64` string, byte
  - `tabletBase64` string, byte
  - `desktopBase64` string, byte
  - `skeletonBase64` string, byte
  - `hydratedBase64` string, byte
  - `timelineBase64` string[]
  - `markdown` string
  - `markdownMeta` MarkdownMetadata
    - `title` string
    - `description` string
    - `finalUrl` string
    - `wordCount` integer
    - `charCount` integer
    - `estimatedTokens` integer
    - `contentQuality` 'ok' | 'likely_blocked' | 'empty' | 'low_text' | 'too_large': Heuristic extraction quality: empty means zero extracted words; low_text means 1-149 words. Callers must still detect target-side blocks and interstitials.
    - `ogTitle` string: og:title, empty when the page declares none.
    - `ogDescription` string: og:description, empty when the page declares none.
    - `ogImage` string: Absolute og:image URL, empty when the page declares none.
  - `links` ExtractedLink[]
    - `text` string, required
    - `href` string, required
  - `interactiveNodes` InteractiveNode[]: Legacy interactive-node summary.
    - `id` union
      - integer
      - string
    - `type` string: The element's tag name.
    - `role` string, nullable: The declared role, or the implicit one resolved from the tag (button, link, checkbox, radio, combobox, textbox).
    - `roleSource` 'explicit' | 'implicit' | 'null', nullable: Whether the page declared the role or it was resolved from the tag.
    - `text` string: The accessible name, truncated to 120 characters.
    - `nameSource` 'text' | 'aria-label' | 'aria-labelledby' | 'value' | 'title' | 'placeholder' | 'alt' | 'null', nullable: Where the name came from. An empty name with a null source is a genuinely unlabelled control — an accessibility defect on the page.
    - `disabled` boolean: Disabled by the attribute or by aria-disabled.
    - `expanded` boolean, nullable: aria-expanded, or null when the element does not declare it.
    - `pressed` boolean, nullable: aria-pressed, or null when the element does not declare it.
    - `placeholder` string, nullable
    - `href` string, nullable
    - `selector` string
    - `box` BoundingBox
      - `x` number, required
      - `y` number, required
      - `width` number, required
      - `height` number, required
      - `viewportX` number
      - `viewportY` number
      - `screenshotX` number
      - `screenshotY` number
      - `screenshotWidth` number
      - `screenshotHeight` number
      - `normalizedX` number
      - `normalizedY` number
      - `normalizedWidth` number
      - `normalizedHeight` number
  - `simplifiedDom` string
  - `performanceMetrics` PerformanceMetrics
    - `fcp` number
    - `lcp` number
    - `ttfb` number
    - `cls` number
  - `actionResults` ActionResult[]
    - `index` integer, required
    - `action` string, required
    - `status` 'passed' | 'failed' | 'skipped', required
    - `durationMs` integer, required
    - `tabId` string
    - `target` string, nullable
    - `code` string
    - `error` string
    - `details` unknown
  - `tabs` string[]: IDs of tabs that remain open after the action sequence.
  - `analysis` Analysis: Structured rich analysis is available on every JSON response mode, including grid and skeleton captures.
    - `semanticSnapshot` union
      - SemanticSnapshot
        - `version` integer, required: Versioned snapshot format identifier.
        - `generatedAt` string, date-time
        - `detail` 'summary' | 'full'
        - `document` SnapshotDocument
          - `title` string
          - `url` string
          - `viewport` SnapshotViewport
            - `width` integer
            - `height` integer
            - `devicePixelRatio` number
        - `nodes` SemanticNode[], required
          - `id` string, required: Per-snapshot evidence ID. It is not a cross-request action locator.
          - `stableKey` string: Node identity based on persistent identifiers or structural position, independent of mutable text and accessible names.
          - `tag` string, required
          - `role` string, nullable
          - `accessibleName` string
          - `text` string
          - `attributes` object: Allowed, non-sensitive attributes only.
          - `form` FormState: Form-control state. Field values are intentionally omitted and valueRedacted is true when a control value existed.
            - `checked` boolean, nullable
            - `disabled` boolean
            - `selected` string[], nullable
            - `required` boolean
            - `readOnly` boolean
            - `valid` boolean, nullable
            - `validationMessage` string
            - `valueRedacted` boolean
          - `parentId` string, nullable
          - `childIds` string[]
          - `visible` boolean, required
          - `inViewport` boolean
          - `box` BoundingBox, required
            - `x` number, required
            - `y` number, required
            - `width` number, required
            - `height` number, required
            - `viewportX` number
            - `viewportY` number
            - `screenshotX` number
            - `screenshotY` number
            - `screenshotWidth` number
            - `screenshotHeight` number
            - `normalizedX` number
            - `normalizedY` number
            - `normalizedWidth` number
            - `normalizedHeight` number
          - `screenshotBox` BoundingBox
            - `x` number, required
            - `y` number, required
            - `width` number, required
            - `height` number, required
            - `viewportX` number
            - `viewportY` number
            - `screenshotX` number
            - `screenshotY` number
            - `screenshotWidth` number
            - `screenshotHeight` number
            - `normalizedX` number
            - `normalizedY` number
            - `normalizedWidth` number
            - `normalizedHeight` number
          - `normalizedBox` BoundingBox
            - `x` number, required
            - `y` number, required
            - `width` number, required
            - `height` number, required
            - `viewportX` number
            - `viewportY` number
            - `screenshotX` number
            - `screenshotY` number
            - `screenshotWidth` number
            - `screenshotHeight` number
            - `normalizedX` number
            - `normalizedY` number
            - `normalizedWidth` number
            - `normalizedHeight` number
          - `normalizedScreenshotBox` NormalizedCoordinateBox
            - `x` number, required
            - `y` number, required
            - `width` number, required
            - `height` number, required
          - `viewportIntersection` ViewportIntersection
            - `intersects` boolean
            - `ratio` number
          - `zIndex` integer, nullable
          - `clickable` boolean
          - `obscuredBy` string, nullable: A redacted description of the element returned by elementFromPoint, when safe to report.
          - `selectorBundles` SelectorCandidate[], required
            - `type` 'css' | 'xpath' | 'text' | 'role' | 'id' | 'name' | 'testId' | 'label' | 'placeholder', required
            - `value` unknown, required
            - `score` number, required
            - `matches` integer, required
            - `unique` boolean: Derived from matches === 1 when included.
            - `brittleness` 'low' | 'medium' | 'high'
            - `reasons` string[]
          - `iframe` IframeNodeMetadata, nullable
            - `src` string, nullable
            - `name` string, nullable
            - `accessible` boolean
        - `frames` FrameMetadata[], required
          - `url` string, required
          - `name` string, nullable
          - `sameOrigin` boolean, required
          - `accessible` boolean, required
        - `truncated` boolean
      - object
        - `beforeActions` SemanticSnapshot
          - `version` integer, required: Versioned snapshot format identifier.
          - `generatedAt` string, date-time
          - `detail` 'summary' | 'full'
          - `document` SnapshotDocument
            - `title` string
            - `url` string
            - `viewport` SnapshotViewport
              - …
          - `nodes` SemanticNode[], required
            - `id` string, required: Per-snapshot evidence ID. It is not a cross-request action locator.
            - `stableKey` string: Node identity based on persistent identifiers or structural position, independent of mutable text and accessible names.
            - `tag` string, required
            - `role` string, nullable
            - `accessibleName` string
            - `text` string
            - `attributes` object: Allowed, non-sensitive attributes only.
            - `form` FormState: Form-control state. Field values are intentionally omitted and valueRedacted is true when a control value existed.
              - …
            - `parentId` string, nullable
            - `childIds` string[]
            - `visible` boolean, required
            - `inViewport` boolean
            - `box` BoundingBox, required
              - …
            - `screenshotBox` BoundingBox
              - …
            - `normalizedBox` BoundingBox
              - …
            - `normalizedScreenshotBox` NormalizedCoordinateBox
              - …
            - `viewportIntersection` ViewportIntersection
              - …
            - `zIndex` integer, nullable
            - `clickable` boolean
            - `obscuredBy` string, nullable: A redacted description of the element returned by elementFromPoint, when safe to report.
            - `selectorBundles` SelectorCandidate[], required
              - …
            - `iframe` IframeNodeMetadata, nullable
              - …
          - `frames` FrameMetadata[], required
            - `url` string, required
            - `name` string, nullable
            - `sameOrigin` boolean, required
            - `accessible` boolean, required
          - `truncated` boolean
        - `afterActions` SemanticSnapshot
          - `version` integer, required: Versioned snapshot format identifier.
          - `generatedAt` string, date-time
          - `detail` 'summary' | 'full'
          - `document` SnapshotDocument
            - `title` string
            - `url` string
            - `viewport` SnapshotViewport
              - …
          - `nodes` SemanticNode[], required
            - `id` string, required: Per-snapshot evidence ID. It is not a cross-request action locator.
            - `stableKey` string: Node identity based on persistent identifiers or structural position, independent of mutable text and accessible names.
            - `tag` string, required
            - `role` string, nullable
            - `accessibleName` string
            - `text` string
            - `attributes` object: Allowed, non-sensitive attributes only.
            - `form` FormState: Form-control state. Field values are intentionally omitted and valueRedacted is true when a control value existed.
              - …
            - `parentId` string, nullable
            - `childIds` string[]
            - `visible` boolean, required
            - `inViewport` boolean
            - `box` BoundingBox, required
              - …
            - `screenshotBox` BoundingBox
              - …
            - `normalizedBox` BoundingBox
              - …
            - `normalizedScreenshotBox` NormalizedCoordinateBox
              - …
            - `viewportIntersection` ViewportIntersection
              - …
            - `zIndex` integer, nullable
            - `clickable` boolean
            - `obscuredBy` string, nullable: A redacted description of the element returned by elementFromPoint, when safe to report.
            - `selectorBundles` SelectorCandidate[], required
              - …
            - `iframe` IframeNodeMetadata, nullable
              - …
          - `frames` FrameMetadata[], required
            - `url` string, required
            - `name` string, nullable
            - `sameOrigin` boolean, required
            - `accessible` boolean, required
          - `truncated` boolean
    - `diagnostics` Diagnostics: Bounded, redacted HAR-like diagnostics. It deliberately omits cookies, authorization, form values, and request/response bodies.
      - `console` ConsoleEvent[]
        - `type` string
        - `text` string
        - `at` string, date-time
      - `pageErrors` PageError[]
        - `message` string
        - `at` string, date-time
      - `failedRequests` FailedRequest[]
        - `url` string
        - `method` string
        - `resourceType` string
        - `error` string
      - `responses` NetworkResponse[]
        - `url` string
        - `method` string
        - `status` integer
        - `resourceType` string
        - `fromCache` boolean
      - `redirects` Redirect[]
        - `from` string
        - `to` string
        - `status` integer
      - `resources` ResourceTiming[]
        - `name` string
        - `initiatorType` string
        - `duration` number
        - `transferSize` integer
        - `encodedBodySize` integer
        - `decodedBodySize` integer
      - `summary` DiagnosticsSummary
        - `consoleCount` integer
        - `pageErrorCount` integer
        - `failedRequestCount` integer
        - `responseCount` integer
        - `resourceCount` integer
        - `thirdPartyDomains` string[]
        - `transferBytes` integer
        - `truncated` boolean
      - `truncated` boolean
    - `extraction` ExtractionResult
      - `fields` object, required
    - `cleanup` CleanupReport
      - `removed` integer
      - `categories` object
  - `probe` boolean
  - `loadTimeMs` integer
  - `bodyTextLength` integer
  - `estimate` ProbeEstimate
    - `remainingBudgetMs` integer
    - `safeScrollActions` integer
    - `safeClickActions` integer
    - `safeTypeActionsAt20Chars` integer
    - `warning` string, nullable

## Other responses

- `202`: The request was explicitly asynchronous or automatically promoted to a durable job.
- `206`: The action budget ended after some action/timeline work completed. metadata.budgetWarning names the budget that applied: 24s synchronous, 52s for async and other worker-executed captures.
- `400`: The request failed validation.
- `403`: The request was refused. Returned when the x-api-key header is missing, revoked, or invalid, and when a valid key is blocked by a plan entitlement, the trusted-JavaScript account entitlement, a global product pause, or a security policy. A plan-only restriction returns code PLAN_FEATURE_UNAVAILABLE and can include upgrade_url. FEATURE_NOT_ENABLED identifies either the global product emergency pause or an eligible Business account without trusted-JavaScript permission; it carries no upgrade_url, so upgrading or retrying cannot clear it. Browser capture can return BROWSER_ISOLATION_REQUIRED or BROWSER_EXECUTION_DENIED with reason public_capture_not_enabled when browser work is unavailable for your account. These platform restrictions carry no upgrade_url and are not resolved by changing plan or key. Check GET /credits for current account capabilities. The API does not use 401: it authenticates with an API key header rather than an HTTP authentication scheme, so there is no WWW-Authenticate challenge to issue.
- `409`: The Idempotency-Key was already used with a different request body.
- `413`: The requested binary response cannot be served synchronously.
- `429`: The plan quota or rate limit has been reached.
- `500`: An unexpected service error occurred.
- `503`: A dependency this request needs is unavailable or not configured for this deployment. Codes: SUPABASE_TIMEOUT and SUPABASE_INVALID_RESPONSE (a storage operation did not answer, or answered unreadably — the write may have committed, so any retry must be idempotent), CAPTURE_ARTIFACT_UNAVAILABLE and CAPTURE_ARTIFACT_CORRUPT (a stored artifact could not be read or parsed), ASYNC_JOBS_NOT_CONFIGURED and CAPTURE_RETRIEVAL_NOT_CONFIGURED (the capability is not configured here, on any plan). Retryable unless the code names a deployment configuration.
- `504`: The browser session timed out during navigation or while executing actions, or did not finish before the synchronous capture deadline (`RENDER_DEADLINE_EXCEEDED`). When frames were captured before an action timeout the body includes partialResult and timelineBase64. Retry with async:true to run outside the synchronous window.

---

[API](https://skmtc.dev/domscout/apis/domscout-api.md) · [All operations](https://skmtc.dev/domscout/apis/domscout-api/llms.txt) · [OpenAPI document](https://skmtc.dev/domscout/apis/domscout-api/revisions/20562d5b5d94?raw)
