Skip to content

Website screenshot API — URL to PNG, JPEG or PDF

Renders a public web page in Chromium and returns the image or PDF. The result is streamed back to you and not stored.

POST https://api.shotvik.com/v1/screenshot
Content-Type: application/json
Authorization: Bearer <api_key>

Authentication: API key in Authorization: Bearer or X-API-Key. PDF is a format of this endpoint ("format": "pdf"); there is no separate PDF endpoint and no GET variant.

Unknown fields are rejected with 400 invalid_request.

Field Type Default Description
url string, required Public http/https URL on port 80 or 443, max 4,096 characters. Private, reserved and local addresses, other ports, non-http(s) schemes and URLs flagged as unsafe are refused.
format png · jpeg · pdf png Output format.
width integer, 100–3840 1280 Viewport width in CSS pixels.
height integer, 100–3840 800 Viewport height in CSS pixels.
full_page boolean false Capture the full scrollable page, capped at 16,384 px height and 50 megapixels.
device_scale_factor number, 1–3 1 Pixel density, e.g. 2 for retina output.
jpeg_quality integer, 1–100 80 Only with format: "jpeg". Sending it with another format returns 400 invalid_request.
wait_until load · domcontentloaded · networkidle · commit load Navigation event to wait for before capturing.
delay_ms integer, 0–10000 0 Extra wait after the page has loaded. Counts toward the 30-second render timeout.
dark_mode boolean false Emulate prefers-color-scheme: dark.
block_ads boolean false Block requests to a list of ad and tracker hosts (request blocking only).
block_cookie_banners boolean false Block requests to common consent-management hosts (request blocking only).
cache boolean false Opt-in cache on our Hetzner servers. Nothing is stored without it. Cache hits don’t count toward your quota.
cache_ttl integer, 60–2592000 86400 Cache lifetime in seconds (max 30 days, provisional). Only used with cache: true.

Success: 200 with the file as the body and Content-Type image/png, image/jpeg or application/pdf.

Header Meaning
X-Request-Id Request ID (req_…). Include it when you contact support. Sent on every response, including errors.
X-Cache HIT (served from your opt-in cache), MISS (rendered and stored in the cache) or BYPASS (cache not requested).
X-Render-Time-Ms, X-Queue-Time-Ms Render time and time spent waiting in the render queue.
X-Target-Status The HTTP status the target site returned.
X-Usage-Used, X-Usage-Limit, X-Usage-Remaining Your monthly usage after this request. Also sent on cache hits, which don’t change it.
X-Usage-Overage true when the render is billed as overage. Overage can’t be turned on yet (see Rate limits and plans), so for now this header isn’t sent.
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset Your per-minute rate limit, what’s left, and seconds until the window resets.
X-Shotvik-Warnings Only present when fonts or images were skipped during the render. See Skipped fonts and images.

Target site errors aren’t API errors. If the target page answers with a 4xx or 5xx status, you still get the rendered page with 200, X-Target-Status shows the target’s status, and the render counts toward your quota. See How usage is counted.

Errors: a JSON body. See Errors. Possible statuses: 400, 401, 403, 413, 429, 500, 502, 503, 504.

Terminal window
curl https://api.shotvik.com/v1/screenshot \
-H "Authorization: Bearer $SHOTVIK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "format": "jpeg", "full_page": true, "jpeg_quality": 85}' \
--fail-with-body --output page.jpg

More languages: Quickstart.

  • Honest rendering: every request’s User-Agent is the headless Chrome string followed by ShotvikBot/0.1 (+https://shotvik.com/bot). The token is always there and can’t be removed or changed. There is no stealth mode, captcha bypass or proxies, and robots.txt isn’t consulted in v1. Sites that block bots will show their block page, which you get as the screenshot. See ShotvikBot.

  • URL safety check: every request a render makes, including redirects and sub-resources, may only go to public http/https addresses on ports 80 and 443. Private, internal and metadata addresses are blocked. Pages and frames are also checked for URL reputation against two sources: the Phishing.Database list (MIT licence) and Shotvik’s own blocklist.

    • If the page itself (or a redirect of it) is refused, you get 403 url_blocked with a reason.
    • A refused sub-resource (image, font, script) is dropped from the page, and the render continues. Skipped fonts and images are reported in X-Shotvik-Warnings.
    • If Shotvik’s copy of Phishing.Database is more than 48 hours old, URL renders are refused with 403 url_blocked and reason reputation_unavailable until it’s updated.
  • Limits per render:

    • render timeout of 30 s in total (including delay_ms);
    • at most 26,214,400 bytes (25 MiB) downloaded and 400 requests; resources beyond the budget aren’t loaded;
    • at most 5 redirects;
    • WebSockets are blocked during renders.

    See Rate limits and plans.

  • No storage by default: the result is streamed and not kept, unless you set cache: true.

When a font or image in the page isn’t loaded, the render still succeeds. The X-Shotvik-Warnings header tells you what was skipped, so a missing web font doesn’t go unnoticed:

X-Shotvik-Warnings: font:blocked:2,image:budget:1
  • The value is a comma-separated list of kind:cause:count.
  • kind is font or image. Other skipped resources, such as scripts or stylesheets, aren’t reported.
  • cause is blocked (refused by the address and port rules above, or by block_ads / block_cookie_banners) or budget (over the per-render limit of 25 MiB or 400 requests).
  • The header is omitted when nothing was skipped. It’s at most 256 bytes; if the list doesn’t fit, it ends with truncated:N.
  • With the opt-in cache, a cache hit returns the same warnings as the original render.