{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/html2img-com/json-schema/html2img-com-screenshot-request-schema.json",
  "title": "ScreenshotRequest",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/_original/html2img-com-api-openapi.json#/components/schemas/ScreenshotRequest",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "url"
  ],
  "properties": {
    "url": {
      "type": "string",
      "format": "uri",
      "description": "The fully qualified, publicly reachable URL to load and capture. Private hosts such as `localhost` and intranet addresses cannot be reached by the renderer."
    },
    "selector": {
      "type": "string",
      "maxLength": 255,
      "description": "Crop the capture to a single CSS selector, for example `#hero` or `main > article`. The first match wins. This endpoint only. Returns `selector_not_found` when nothing matches."
    },
    "css": {
      "type": "string",
      "description": "Extra CSS injected after the page loads, applied last so it wins over the page's own stylesheets. Use it to hide cookie banners and chat widgets, force a colour scheme, or theme one template two ways."
    },
    "width": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5000,
      "default": 1440,
      "description": "Viewport width in CSS pixels. 1200 for Open Graph and Twitter cards, 1080 for square social crops, 1280 or 1920 for desktop captures. Multiplied by `dpi` to give the final pixel width."
    },
    "height": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5000,
      "default": 900,
      "description": "Viewport height in CSS pixels. Ignored when `fullpage` is true, and ignored for PDF output (pages are always A4 portrait). 630 for Open Graph cards, 1080 for square crops."
    },
    "fullpage": {
      "type": "boolean",
      "default": false,
      "description": "Capture the entire scroll height rather than just the viewport. `height` is ignored, and DPI is forced to 1 because full-page renders are already large. No effect on PDF output."
    },
    "dpi": {
      "type": "integer",
      "minimum": 1,
      "maximum": 4,
      "description": "Device pixel ratio multiplier. Defaults to 2 on /html and 1 on /screenshot. Use 2 for anything shown on a modern phone or laptop, 3 only for print or marketing assets. Pair 3 with `webhook_url`: the render usually exceeds the 30 second synchronous budget. Ignored for PDF output, which is vector."
    },
    "format": {
      "type": "string",
      "enum": [
        "png",
        "pdf"
      ],
      "default": "png",
      "description": "Output container. `pdf` produces a real vector PDF with selectable text and embedded fonts, laid out on A4 portrait pages that paginate automatically. A PDF costs the same single credit as a PNG. With `pdf`, the parameters `dpi`, `fullpage` and `selector` have no effect."
    },
    "scale_to_fit": {
      "type": "boolean",
      "default": false,
      "description": "PDF output only. Lays the content out at the requested `width`, then scales the whole layout down so it fits the A4 page width instead of being cropped, and trims a trailing blank page. This is how you keep a desktop layout in a PDF. Ignored for PNG."
    },
    "ms_delay": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5000,
      "description": "Wait this many milliseconds after load before capturing, for entry animations, lazy embeds or iframes. Prefer `wait_for_selector` when the page has a known readiness marker."
    },
    "wait_for_selector": {
      "type": "string",
      "description": "Wait until this CSS selector appears in the DOM before capturing, with a 15 second limit. The reliable way to handle client-side charts and other JavaScript-driven content. Returns `selector_timeout` if it never appears."
    },
    "webhook_url": {
      "type": "string",
      "format": "uri",
      "description": "Switches the request to async mode. The API responds immediately with `status: \"processing\"` and POSTs the finished render to this URL. Recommended whenever a render might exceed the 30 second synchronous budget: large full-page captures, DPI 3, or JavaScript-heavy pages. Delivery is attempted once, with no retry."
    }
  }
}