/api/v1/screenshotCapture pixel-perfect screenshots of any publicly accessible URL. Supports custom viewports, full page capture, element selectors, delays, and multiple output formats.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| url | string | Yes | - | The URL to screenshot. Must be publicly accessible and start with http:// or https://. |
| width | number | No | 1280 | Viewport width in pixels. Range: 320-3840. |
| height | number | No | 720 | Viewport height in pixels. Range: 240-2160. |
| format | string | No | png | Output format: png, jpeg, or webp. Available on every plan. |
| fullPage | boolean | No | false | Capture the full scrollable page instead of just the viewport. Available on every plan, including Free. Also accepted as full_page. |
| block_cookie_banners | boolean | No | true | Remove consent/cookie banners before capturing. On by default. Set to false to keep them. Also accepted as hide_cookie_banners. |
| block_chats | boolean | No | true | Remove chat launchers and support bubbles (Intercom, Drift, Crisp, Zendesk and similar). |
| accept_cookie_banners | boolean | No | false | Click “Accept all” instead of hiding the banner. Only needed for sites that withhold content until consent is given — note this records consent on your behalf. |
| wait_until | string | No | domcontentloaded | Navigation signal: load, domcontentloaded, networkidle0 or networkidle2. The default suits almost every page; use networkidle2 for SPAs that render late. |
| timeout | number | No | 15000 | Navigation budget in ms (1000–20000). If it expires but the page has rendered, you get that capture with X-Capture-Degraded: true rather than an error. |
| full_page_max_height | number | No | 20000 | Clip a full-page capture past this height (1000–30000 px). When it applies, the response carries X-Capture-Truncated and X-Capture-Page-Height. |
| user_agent | string | No | - | Override the User-Agent sent to the target site. |
| block_fonts | boolean | No | false | Skip downloading web fonts for a faster capture. Off by default because blocking fonts changes text metrics and breaks icon fonts. |
| delay | number | No | 0 | Wait time in milliseconds after page load before capturing. Max: varies by plan. |
| selector | string | No | - | CSS selector to capture a specific element instead of the full viewport. |
| quality | number | No | 80 | Image quality for JPEG/WebP format. Range: 1-100. |
| device_scale_factor | number | No | 1 | Device pixel ratio (1 for standard, 2 for retina). Range: 1-3. Also accepted as deviceScaleFactor. With fullPage=true the render is capped at 2 — a whole page at 3 exceeds what the renderer can hold — and the response then carries X-Capture-Scale-Clamped: 3 (and scale_clamped in JSON) so you never have to guess. |
| json | boolean | No | false | Return a JSON response with the image as a base64 data URL instead of raw binary, plus capture metadata. |
By default, the API returns the screenshot as binary image data with the appropriate Content-Type header. Use ?json=true to receive a JSON response instead.
Content-Type: image/png
Content-Length: 245678
X-Request-Id: req_abc123
X-RateLimit-Remaining: 49
X-Capture-Duration: 1250ms
# Present only when they apply — each one is a caveat about the image itself:
X-Capture-Page-Height: 12635 # measured document height (full-page requests)
X-Capture-Truncated: true # the page was taller than the limit and was clipped
X-Capture-Degraded: true # navigation timed out; you got the painted page anyway
X-Capture-Overlays-Hidden: 2 # consent banners / chat widgets removed
X-Capture-Images-Pending: 4 # images that had not finished loading when capturedThese headers are the same on a cached response as on a fresh render: the bytes are identical, so every caveat that applied to them still applies.
With fullPage=true we scroll through the document before capturing, so images that load on scroll actually load, and sections that reveal on scroll are visible. Without this a full-page capture of a modern site comes back with grey rectangles where the photographs should be — delay cannot fix that, because waiting longer does not make a scroll-triggered loader fire. The walk is time-bounded and adds a few seconds to full-page requests only; viewport captures are unaffected. Any images that still had not arrived are reported in X-Capture-Images-Pending rather than left for you to spot.
| Code | Status | Meaning |
|---|---|---|
| URL_UNREACHABLE | 400 | The URL could not be reached — DNS failure, refused connection, or a typo. |
| SELECTOR_NOT_FOUND | 422 | No element matched your selector. |
| TARGET_RENDERED_NOTHING | 502 | The page loaded but painted nothing, so the image would have been a blank rectangle. Usually a site that turns automated browsers away. This does not consume a credit. |
| CAPTURE_TIMEOUT | 504 | The page never rendered within the navigation budget. Raise timeout, or target a selector. |
| CAPTURE_BUSY | 503 | The engine is at capacity. Retry in a few seconds. |
A failed capture never costs a credit: the reservation is released before the error reaches you.
# Basic screenshot
curl "https://captureapi.dev/api/v1/screenshot?url=https://github.com" \
-H "X-API-Key: cap_your_key" \
-o github.png
# Full page, high resolution
curl "https://captureapi.dev/api/v1/screenshot?url=https://github.com&fullPage=true&width=1920&height=1080&format=webp&device_scale_factor=2" \
-H "X-API-Key: cap_your_key" \
-o github-full.webp
# Capture specific element
curl "https://captureapi.dev/api/v1/screenshot?url=https://github.com&selector=.application-main" \
-H "X-API-Key: cap_your_key" \
-o github-main.pngasync function captureScreenshot(url, options = {}) {
const params = new URLSearchParams({
url,
width: options.width?.toString() || "1280",
height: options.height?.toString() || "720",
format: options.format || "png",
...(options.fullPage && { fullPage: "true" }),
...(options.delay && { delay: options.delay.toString() }),
...(options.selector && { selector: options.selector }),
});
const response = await fetch(
`https://captureapi.dev/api/v1/screenshot?${params}`,
{
headers: { "X-API-Key": process.env.CAPTURE_API_KEY }
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
return response.arrayBuffer();
}
// Usage
const screenshot = await captureScreenshot("https://example.com", {
width: 1920,
height: 1080,
format: "webp",
fullPage: true
});import requests
import os
def capture_screenshot(url, **kwargs):
params = {
"url": url,
"width": kwargs.get("width", 1280),
"height": kwargs.get("height", 720),
"format": kwargs.get("format", "png"),
}
if kwargs.get("full_page"):
params["fullPage"] = "true"
if kwargs.get("delay"):
params["delay"] = kwargs["delay"]
if kwargs.get("selector"):
params["selector"] = kwargs["selector"]
response = requests.get(
"https://captureapi.dev/api/v1/screenshot",
params=params,
headers={"X-API-Key": os.environ["CAPTURE_API_KEY"]}
)
response.raise_for_status()
return response.content
# Usage
screenshot = capture_screenshot(
"https://example.com",
width=1920,
height=1080,
format="webp",
full_page=True
)
with open("screenshot.webp", "wb") as f:
f.write(screenshot)package main
import (
"io"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET",
"https://captureapi.dev/api/v1/screenshot?url=https://example.com&width=1920&height=1080&format=webp&fullPage=true", nil)
req.Header.Set("X-API-Key", os.Getenv("CAPTURE_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
f, _ := os.Create("screenshot.webp")
defer f.Close()
io.Copy(f, resp.Body)
}require "net/http"
require "uri"
uri = URI("https://captureapi.dev/api/v1/screenshot?url=https://example.com&width=1920&height=1080&format=webp&fullPage=true")
req = Net::HTTP::Get.new(uri)
req["X-API-Key"] = ENV["CAPTURE_API_KEY"]
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http|
http.request(req)
}
File.open("screenshot.webp", "wb") { |f| f.write(res.body) }<?php
$url = "https://captureapi.dev/api/v1/screenshot?" . http_build_query([
"url" => "https://example.com",
"width" => 1920,
"height" => 1080,
"format" => "webp",
"fullPage" => "true",
]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"X-API-Key: " . getenv("CAPTURE_API_KEY")
]);
$response = curl_exec($ch);
curl_close($ch);
file_put_contents("screenshot.webp", $response);
?>| Plan | Monthly Limit | Max Resolution | Timeout | Formats |
|---|---|---|---|---|
| Free | 200 | 4K | 60s | PNG, JPEG, WebP |
| Starter | 2,000 | 4K | 60s | PNG, JPEG, WebP |
| Pro | 15,000 | 4K | 60s | All |
| Business | 50,000 | 4K | 60s | All |
| Enterprise | 999,999 | 4K | 60s | All |