# Take a screenshot

`GET` `POST` `/v1/screenshot`

Takes a screenshot of a public web page and waits for it. By default the answer is the image. With `GET`, options go in the address. With `POST`, they go in a JSON body.

**GET, options in the address**

```bash
curl "https://api.localscreenshot.com/v1/screenshot?url=https://www.wikipedia.org&device=iphone_15&full_page=true" \
  -H "Authorization: Bearer $LOCALSCREENSHOT_API_KEY" \
  -o shot.png
```

**POST, options in a JSON body**

```bash
curl -X POST "https://api.localscreenshot.com/v1/screenshot" \
  -H "Authorization: Bearer $LOCALSCREENSHOT_API_KEY" \
  -H "Idempotency-Key: order-2026-10-08-001" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.wikipedia.org",
    "device": "iphone_15",
    "full_page": true,
    "block_cookie_banners": true,
    "format": "jpeg",
    "response": "json"
  }'
```

## Headers

| Header | Description |
| --- | --- |
| `Authorization` (required) | `Bearer` followed by your API key. The key is never accepted in the address. See [Your API key](https://docs.localscreenshot.com/auth). |
| `Idempotency-Key` | Makes a retry safe: the same key returns the same screenshot and is charged once. 8 to 128 letters, digits, dashes, dots, colons or underscores. See [Retries and Idempotency-Key](https://docs.localscreenshot.com/retries). |

## What to capture

| Parameter | Type | Description |
| --- | --- | --- |
| `url` (required) | string | The public http or https page to capture. |
| `full_page` | boolean | Capture the whole scrollable page instead of the visible part.  Default: `false`. |
| `selector` | string | Capture only the first element matching this CSS selector. Up to 200 characters. |
| `hide_selectors` | array | Hide every element matching these CSS selectors. In a URL, separate them with commas. Up to 20. |

## How it looks

| Parameter | Type | Description |
| --- | --- | --- |
| `viewport` | string | Screen size as WIDTHxHEIGHT, for example 1440x900. Shortcut for viewport_width and viewport_height. |
| `viewport_width` | integer | Width of the browser window, in pixels. 320 to 3,840. Default: `1440`. |
| `viewport_height` | integer | Height of the browser window, in pixels. With full_page, the image is taller than this. 320 to 2,160. Default: `900`. |
| `device` | string | Capture as this device (screen size, pixel density, mobile browser). One of `desktop`, `desktop_hd`, `laptop`, `ipad`, `ipad_pro`, `ipad_mini`, `iphone_15`, `iphone_15_pro_max`, `iphone_se`, `pixel_8`, `galaxy_s24`. |
| `device_scale_factor` | number | Pixel density. 2 gives a sharper, larger image. 1 to 3. Default: `1`. |
| `color_scheme` | string | Ask the page for its light or dark theme. One of `light`, `dark`. |
| `language` | string | Browser language, for example fr or fr-FR.  Default: `en-US`. |
| `timezone` | string | Browser time zone, for example Europe/Paris. |
| `country` | string | Load the page from this country (ISO 3166-1 alpha-2 code, see /v1/countries). The response reports the country actually observed. If it cannot be obtained, the request fails and is not charged. Costs 2 credits instead of 1. |

> **Not open to every account yet.** Screenshots from a chosen country are being opened account by account. Until yours is, a request with `country` is refused with `option_unavailable` before anything is captured.

## Clean up

| Parameter | Type | Description |
| --- | --- | --- |
| `block_cookie_banners` | boolean | Removes most cookie banners. A banner the filters do not know stays in the picture.  Default: `false`. |
| `block_ads` | boolean | Block ads.  Default: `false`. |
| `block_chat_widgets` | boolean | Hide chat bubbles.  Default: `false`. |
| `close_popups` | boolean | Close pop-ups and newsletter overlays.  Default: `false`. |
| `hide_sticky_elements` | boolean | Hide headers, bars and buttons that stay fixed on screen.  Default: `false`. |
| `disable_animations` | boolean | Freeze animations and transitions.  Default: `false`. |

## When

| Parameter | Type | Description |
| --- | --- | --- |
| `wait_for` | string | Wait until an element matching this CSS selector is visible. Up to 200 characters. |
| `delay_ms` | integer | Extra wait before the capture, in milliseconds. 0 to 5,000. Default: `0`. |

We wait for the page to load and for its network to calm down before the picture. Use `wait_for` when the part you want appears late, and `delay_ms` for an animation that needs a moment.

## What comes back

| Parameter | Type | Description |
| --- | --- | --- |
| `format` | string | File format. pdf saves the whole page as a document; it cannot be combined with selector or max_width. One of `png`, `jpeg`, `webp`, `pdf`. Default: `png`. |
| `quality` | integer | Quality for jpeg and webp. Ignored for png and pdf. 1 to 100. Default: `80`. |
| `max_width` | integer | Scale the image down to this width. Useful to keep it small for a vision model. 320 to 3,840. |
| `response` | string | image returns the picture itself. json returns its link, the page details and the attestation. One of `image`, `json`. Default: `image`. |
| `async` | boolean | Return an id right away instead of waiting. Read the result at /v1/screenshots/{id}.  Default: `false`. |

> An option we do not know is refused with `invalid_request`, never ignored. `selector` and `full_page` cannot be used together. A `pdf` is always the whole page: it cannot be combined with `selector` or `max_width`.

## Response

The image, with these headers. With `response=json`, a JSON document instead. If the screenshot is still running when the wait ends (after 50 seconds), or with `async=true`, you get `202` and a `Location` header to read it later: see [Run in the background](https://docs.localscreenshot.com/async).

| Header | Description |
| --- | --- |
| `X-Screenshot-Id` | The id of the screenshot. |
| `X-Credits-Charged` | Credits this screenshot used. |
| `X-Credits-Remaining` | Credits you have left. |
| `X-Page-Status` | What the page answered, for example 200 or 404. A page that answers 404 or 451 is still captured and charged. |
| `X-Country-Observed` | Only with `country`: the country the page was really loaded from. |

A `pdf` is sent as a file to download, not shown in the browser.

**200, with response=json**

```json
{
  "id": "01JABCDEF2G3H4J5K6M7N8P9QR",
  "status": "succeeded",
  "created_at": "2026-10-08T10:47:02Z",
  "finished_at": "2026-10-08T10:47:06Z",
  "image": {
    "url": "https://api.localscreenshot.com/v1/screenshots/01JABC.../image?expires=...&signature=...",
    "mime": "image/jpeg",
    "bytes": 412840,
    "width": 1179,
    "height": 8421,
    "pages": null,
    "sha256": "a5b9081b8430...",
    "truncated": false,
    "available_until": "2026-10-15T10:47:02Z"
  },
  "page": { "status": 200, "final_url": "https://www.wikipedia.org/", "title": "Wikipedia", "redirects": [] },
  "country": null,
  "attestation": null,
  "credits": { "charged": 1, "reserved": 1, "remaining": 49 },
  "error": null,
  "links": { "self": "https://api.localscreenshot.com/v1/screenshots/01JABC..." }
}
```

## Limits of one screenshot

- Only public `http` and `https` pages. A private or local address is refused with `url_not_allowed`.
- A page has 35 seconds to load. After that the screenshot fails with `timeout`.
- A page heavier than 10 MB to download fails with `page_too_heavy`. Video and audio are not loaded.
- When a site shows a bot check instead of its page, the screenshot fails with `challenge_page`. We do not solve CAPTCHAs.

Every code is on [Errors](https://docs.localscreenshot.com/errors).
