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

# Website screenshots

> Capture public webpages as PNG images with configurable viewport, device, and theme.

Pirehub captures a public webpage and returns a PNG data URI in the standard JSON
success envelope. Choose a viewport capture or set `fullPage: true` to capture
the full page.

## Authentication

`POST /api/v1/screenshot` accepts a Pirehub API key with the `screenshot:capture`
scope for server-to-server integrations. Send the key in `x-pirehub-api-key` or
as a bearer token. Keep the key on your server.

Pirehub's website can use the alternative described in
[First-party browser verification](/api-reference/authentication#first-party-browser-verification).
External integrations should use a scoped API key.

## Capture options

| Field                 | Required | Accepted values                                                                         |
| --------------------- | -------- | --------------------------------------------------------------------------------------- |
| `url`                 | Yes      | Public HTTP(S) URL, at most 2048 characters                                             |
| `width`               | Yes      | Integer viewport width from 300 to 1920 pixels                                          |
| `height`              | Yes      | Integer viewport height from 168 to 4096 pixels                                         |
| `fullPage`            | Yes      | `true` for the full page; `false` for the viewport                                      |
| `device`              | No       | `desktop` (default) or `mobile`                                                         |
| `theme`               | No       | `light` (default) or `dark`                                                             |
| `delay`               | No       | Additional delay: `0` (default), `2000`, or `5000` milliseconds                         |
| `refreshCache`        | No       | `false` (default); `true` to request a fresh capture                                    |
| `showParentPost`      | No       | X posts only: include an available parent post; defaults to `true`                      |
| `postWidth`           | No       | X posts only: `s` (default, 640 CSS px), `m` (800), or `l` (960)                        |
| `includePostVariants` | No       | X posts only: `true` to return all three layouts for local editing; defaults to `false` |

URLs containing credentials, private network targets, and ports other than 80 or
443 are rejected. Sites that require login or block automated capture may not
produce an image.

## Capture request

```bash theme={null}
curl --request POST \
  --url https://www.ntanduy.com/api/v1/screenshot \
  --header 'Content-Type: application/json' \
  --header "x-pirehub-api-key: $PIREHUB_API_KEY" \
  --data '{
    "url": "https://example.com",
    "width": 1280,
    "height": 720,
    "fullPage": false,
    "device": "desktop",
    "theme": "light",
    "delay": 0,
    "refreshCache": false
  }'
```

## X posts

Public X/Twitter status URLs produce a post card with any available media and
quoted post. Set `showParentPost: false` to omit the parent post. `postWidth`
controls the card's layout width; cards render at 3× density and are scaled down
if an output dimension exceeds 8192 pixels. Website viewport, device, theme,
delay, and full-page options do not affect post cards. The required `width`,
`height`, and `fullPage` fields must still be valid.

```json theme={null}
{
  "url": "https://x.com/thsottiaux/status/2104467346945675347?s=20",
  "width": 1280,
  "height": 960,
  "fullPage": false,
  "showParentPost": true,
  "postWidth": "s"
}
```

Parent visibility and card width are included in the cache identity.

For interactive editing, set `includePostVariants: true` on the initial request.
The response adds `data.postVariants.s`, `.m`, and `.l`, each containing a PNG
`dataUrl`, pixel `width`/`height`, `parentHeight`, and `topPadding`. These variants
include the available parent regardless of `showParentPost`; the main `dataUrl`
still follows the requested options. This increases the initial response size.
The combined PNG variant data is limited to 12 MiB before base64 encoding;
larger sets return `422 VALIDATION_ERROR`.
Changing layouts then requires no additional API call. To hide the parent locally,
copy from `parentHeight + topPadding` to the bottom of the variant into a canvas
of height `height - parentHeight`, starting at `topPadding`, on a `#0b0d10`
background. If `parentHeight` is zero, use the original image.

The screenshot editor uses this mode after Capture. Its S/M/L and parent controls
update the current preview locally; Capture remains available to fetch fresh data.

## Capture response

```json theme={null}
{
  "success": true,
  "data": {
    "dataUrl": "data:image/png;base64,...",
    "width": 1280,
    "height": 720,
    "cached": false
  }
}
```

The image data is abbreviated in this example. `data.width` and `data.height`
describe the actual output image; full-page capture can produce a height different
from the requested viewport. Decode the base64 portion of `data.dataUrl` to save
a PNG, or use the complete data URI as an image source.

## Caching

Matching captures may be cached for up to 15 minutes, or 10 minutes for supported tweet
URLs. Cache entries can be evicted earlier. `data.cached: true` indicates a cached result. Set `refreshCache: true` to
request a fresh capture. Cache hits still count toward the API key's limits.

## Limits and failures

API-key requests use the per-minute and monthly limits configured for that key.
Inspect `X-ApiKey-RateLimit-*` and `X-ApiKey-Monthly-*`. First-party browser requests
without an API key are limited to 5 requests per minute per IP and return
`X-RateLimit-*` headers.

Capture processing has an 18-second deadline. A busy capture service returns
`429 RATE_LIMITED`; temporary capacity constraints return `503 SERVICE_UNAVAILABLE`.
Retry after a short delay rather than sending parallel capture requests.
Full-page website images are capped at 8192 pixels in height.
Capture scrolls through that range to trigger lazy content, waits briefly for
images and fonts, and renders offscreen CSS containment sections. Login walls,
CAPTCHAs, virtualized lists, infinite feeds, or content that loads after the
deadline can prevent a complete capture.

| HTTP status         | Code                     | Meaning                                                    |
| ------------------- | ------------------------ | ---------------------------------------------------------- |
| `400`               | `VALIDATION_ERROR`       | Invalid capture options or a disallowed URL                |
| `401`               | `UNAUTHORIZED`           | Invalid API key                                            |
| `403`               | `FORBIDDEN`              | The key is revoked, expired, or lacks `screenshot:capture` |
| `422`               | `VALIDATION_ERROR`       | The page blocks capture or the content is too tall         |
| `429`               | `RATE_LIMITED`           | A request rate limit was reached                           |
| `429`               | `MONTHLY_QUOTA_EXCEEDED` | The key's monthly quota is exhausted                       |
| `502`, `503`, `504` | See error response       | Capture failed, is unavailable, or timed out               |

Honor `Retry-After` when present. After monthly quota exhaustion, wait until the
reported reset time. See [Errors and retries](/api-reference/errors).

## Next steps

<Columns cols={3}>
  <Card title="Screenshot endpoint" icon="code" href="/api-reference/endpoint/screenshot">
    Review the complete request and response schemas.
  </Card>

  <Card title="Authentication" icon="key" href="/api-reference/authentication">
    Learn about scopes and credential handling.
  </Card>

  <Card title="Errors and retries" icon="triangle-exclamation" href="/api-reference/errors">
    Handle failures safely and predictably.
  </Card>
</Columns>
