Screenshot API
Complete reference for the GET /api/v1/screenshot endpoint — capture any web page as an image.
Endpoint
GET /api/v1/screenshot
POST /api/v1/screenshotCaptures a screenshot of the specified URL (or raw HTML via POST) and returns the binary image data directly in the response body. Requires API key authentication. Use POST when sending raw HTML via the html body parameter.
Authentication
Include your API key in one of these headers:
| Header | Format |
|---|---|
x-api-key | sk_live_your_key_here |
Authorization | Bearer sk_live_your_key_here |
Query Parameters
Required
| Parameter | Type | Description |
|---|---|---|
url | string | The URL of the page to screenshot. Must be a valid, fully-qualified URL (including https://). |
Optional
| Parameter | Type | Default | Description |
|---|---|---|---|
width | number | 1440 | Viewport width in pixels. Maximum: 1920. |
height | number | 900 | Viewport height in pixels. Maximum: 10000. |
fullPage | string | "false" | Set to "true" to capture the entire scrollable page. Ignores the height parameter when enabled. |
type | string | "png" | Image format: "png", "jpeg", "webp", or "pdf". |
quality | number | 100 | Image quality from 1 to 100. Only applies to JPEG and WebP formats. Ignored for PNG. |
colorScheme | string | — | Force color scheme: "light" or "dark". Emulates the prefers-color-scheme media feature. |
waitUntil | string | "networkidle2" | Page load event to wait for before capturing. See Wait Strategies. |
waitForSelector | string | — | CSS selector to wait for before capturing. The screenshot is taken once this element exists in the DOM. |
delay | number | 0 | Additional delay in milliseconds after the page loads and before the screenshot is taken. Range: 0–30000. |
blockAds | boolean | false | Enable ad blocking. Removes ads from the page before capture. |
removeCookieBanners | boolean | false | Auto-remove cookie consent dialogs before capture. |
cssInject | string | — | Inject custom CSS into the page before capture. Useful for hiding elements or overriding styles. |
jsInject | string | — | Inject custom JavaScript into the page before capture. Runs after the page loads but before the screenshot is taken. |
stealthMode | boolean | false | Enable anti-bot-detection mode. Masks headless browser fingerprints to avoid being blocked by bot-detection systems. |
devicePixelRatio | number | 1 | Device pixel ratio for Retina/HiDPI captures. Accepted values: 1, 2, or 3. Higher values produce larger, sharper images. |
timezone | string | — | Timezone emulation (e.g. "America/New_York"). Overrides the browser's default timezone for the capture. |
locale | string | — | Locale and Accept-Language emulation (e.g. "en-US"). Controls the language used by the browser during the capture. |
cacheTtl | number | 0 | Response cache TTL in seconds. When set to a value greater than 0, identical requests within the TTL window return a cached response. Set to 0 to disable caching. |
preloadFonts | boolean | false | Preload all Google Fonts on the page before capture. Ensures accurate font rendering by explicitly loading every font discovered in the page's stylesheets. |
removeElements | string | — | Comma-separated CSS selectors for elements to remove before capture. Example: ".popup, #banner, .newsletter-signup". Each matching element is removed from the DOM. |
removePopups | boolean | false | Automatically remove common popups, modals, overlays, and interstitials before capture. Targets elements with position: fixed/sticky and high z-index that match popup-like class names. |
mockupDevice | string | — | Wrap the screenshot in a device frame. Values: "browser" (macOS chrome), "iphone" (iPhone with Dynamic Island), "macbook" (MacBook with bezel). Output is always PNG. |
geoLatitude | number | — | Latitude for browser geolocation override. Must be used together with geoLongitude. |
geoLongitude | number | — | Longitude for browser geolocation override. Must be used together with geoLatitude. |
geoAccuracy | number | 100 | Accuracy in meters for the geolocation override. Only applies when geoLatitude and geoLongitude are set. |
POST-only Body Parameters
| Parameter | Type | Description |
|---|---|---|
html | string | Raw HTML string to render instead of navigating to a URL. When provided, the url parameter is ignored. Must use POST method with a JSON body. |
Wait Strategies
The waitUntil parameter controls when the page is considered "loaded":
| Value | Description |
|---|---|
load | Waits for the load event (all resources including images loaded). |
domcontentloaded | Waits for the DOMContentLoaded event (HTML parsed, but images/stylesheets may still be loading). |
networkidle0 | Waits until there are no more than 0 network connections for 500ms. Best for fully static content. |
networkidle2 | Waits until there are no more than 2 network connections for 500ms. Default. Good balance for most pages, tolerates long-polling or analytics connections. |
For single-page applications (SPAs) that load content dynamically, combine waitUntil: "networkidle2" with waitForSelector targeting a key content element, or add a delay.
Response
Success (200)
Headers:
| Header | Type | Description |
|---|---|---|
Content-Type | string | image/png, image/jpeg, image/webp, or application/pdf |
x-credits-remaining | string | Your remaining credit balance |
x-screenshot-id | string | Unique identifier for this screenshot |
x-duration-ms | string | Time taken to capture the screenshot in milliseconds |
Body: Binary image data.
Error Responses
| Status | Body | Description |
|---|---|---|
401 | {"error": "API key required"} | No API key provided |
402 | {"error": "Insufficient credits", "balance": 0} | Not enough credits |
403 | {"error": "Invalid API key"} | API key is invalid or revoked |
Examples
Basic Screenshot
curl "https://screenshotapi.to/api/v1/screenshot?url=https://example.com" \
-H "x-api-key: sk_live_your_key_here" \
--output screenshot.pngconst response = await fetch(
'https://screenshotapi.to/api/v1/screenshot?url=https://example.com',
{ headers: { 'x-api-key': 'sk_live_your_key_here' } }
)
if (!response.ok) {
const error = await response.json()
throw new Error(error.message)
}
const buffer = Buffer.from(await response.arrayBuffer())
await fs.promises.writeFile('screenshot.png', buffer)import requests
response = requests.get(
"https://screenshotapi.to/api/v1/screenshot",
params={"url": "https://example.com"},
headers={"x-api-key": "sk_live_your_key_here"}
)
response.raise_for_status()
with open("screenshot.png", "wb") as f:
f.write(response.content)req, _ := http.NewRequest("GET",
"https://screenshotapi.to/api/v1/screenshot?url=https://example.com", nil)
req.Header.Set("x-api-key", "sk_live_your_key_here")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
file, _ := os.Create("screenshot.png")
defer file.Close()
io.Copy(file, resp.Body)require "net/http"
require "uri"
uri = URI("https://screenshotapi.to/api/v1/screenshot?url=https://example.com")
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = "sk_live_your_key_here"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http|
http.request(req)
}
File.binwrite("screenshot.png", response.body)$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://screenshotapi.to/api/v1/screenshot?url=https://example.com",
CURLOPT_HTTPHEADER => ["x-api-key: sk_live_your_key_here"],
CURLOPT_RETURNTRANSFER => true,
]);
$image = curl_exec($ch);
curl_close($ch);
file_put_contents("screenshot.png", $image);Full-Page Screenshot
Capture the entire scrollable page as a single tall image:
curl "https://screenshotapi.to/api/v1/screenshot?url=https://example.com&fullPage=true&type=webp&quality=90" \
-H "x-api-key: sk_live_your_key_here" \
--output fullpage.webpconst params = new URLSearchParams({
url: 'https://example.com',
fullPage: 'true',
type: 'webp',
quality: '90'
})
const response = await fetch(
`https://screenshotapi.to/api/v1/screenshot?${params}`,
{ headers: { 'x-api-key': 'sk_live_your_key_here' } }
)
const buffer = Buffer.from(await response.arrayBuffer())
await fs.promises.writeFile('fullpage.webp', buffer)import requests
response = requests.get(
"https://screenshotapi.to/api/v1/screenshot",
params={
"url": "https://example.com",
"fullPage": "true",
"type": "webp",
"quality": "90"
},
headers={"x-api-key": "sk_live_your_key_here"}
)
with open("fullpage.webp", "wb") as f:
f.write(response.content)req, _ := http.NewRequest("GET",
"https://screenshotapi.to/api/v1/screenshot?url=https://example.com&fullPage=true&type=webp&quality=90", nil)
req.Header.Set("x-api-key", "sk_live_your_key_here")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
file, _ := os.Create("fullpage.webp")
defer file.Close()
io.Copy(file, resp.Body)require "net/http"
require "uri"
uri = URI("https://screenshotapi.to/api/v1/screenshot?url=https://example.com&fullPage=true&type=webp&quality=90")
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = "sk_live_your_key_here"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http|
http.request(req)
}
File.binwrite("fullpage.webp", response.body)$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://screenshotapi.to/api/v1/screenshot?url=https://example.com&fullPage=true&type=webp&quality=90",
CURLOPT_HTTPHEADER => ["x-api-key: sk_live_your_key_here"],
CURLOPT_RETURNTRANSFER => true,
]);
$image = curl_exec($ch);
curl_close($ch);
file_put_contents("fullpage.webp", $image);Dark Mode Screenshot
Force dark mode rendering on any page that supports prefers-color-scheme:
curl "https://screenshotapi.to/api/v1/screenshot?url=https://example.com&colorScheme=dark" \
-H "x-api-key: sk_live_your_key_here" \
--output dark.pngCustom Viewport Size
Capture at a mobile viewport size:
curl "https://screenshotapi.to/api/v1/screenshot?url=https://example.com&width=390&height=844" \
-H "x-api-key: sk_live_your_key_here" \
--output mobile.pngWait for Dynamic Content
Wait for a specific element to appear before capturing:
curl "https://screenshotapi.to/api/v1/screenshot?url=https://example.com&waitForSelector=.hero-loaded&delay=500" \
-H "x-api-key: sk_live_your_key_here" \
--output dynamic.pngRate Limits
There are currently no enforced rate limits. However, screenshots are generated sequentially per API key. For maximum throughput, use multiple API keys or send requests in parallel — each request will be queued and processed as resources become available.
Best Practices
- Use
networkidle2(the default) for most pages. It handles analytics scripts and long-polling gracefully. - Use
waitForSelectorfor SPAs where content loads asynchronously after the initial page load. - Use WebP format for smaller file sizes when quality is acceptable (typically 30–50% smaller than PNG).
- Set appropriate viewport dimensions — the default 1440×900 works for most desktop pages, but use 390×844 for mobile screenshots.
- Add a small
delay(200–500ms) for pages with CSS animations or transitions that should complete before capture.