API Documentation
Everything you need to capture screenshots with the SnapRender API.
Quick Start
Get your API key from the dashboard, then make a request:
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=png" \
-H "X-API-Key: YOUR_API_KEY" \
--output screenshot.png
That's it. The API returns the screenshot binary directly. For JSON metadata + base64 image, add response_type=json.
Authentication
All API requests require an API key passed in the X-API-Key header.
X-API-Key: sk_live_your_key_here
API keys start with sk_live_ and are 40 characters long.
Create and manage keys in the dashboard. Keys are hashed server-side and shown only once at creation.
Missing or invalid keys return 401 UNAUTHORIZED.
Base URL
https://app.snap-render.com
All endpoints below are relative to this base URL. HTTPS is required.
Endpoints
/v1/screenshot
Capture a screenshot of any public URL. Returns the image binary by default, or JSON with base64 data when response_type=json.
Requires API key. Counts against monthly quota.
See Parameters for all options and Response Format for output details.
/v1/screenshot/info
Check if a screenshot is cached without taking a new one. Accepts the same query parameters as /v1/screenshot. Does not count against quota.
Response:
{
"url": "https://example.com",
"cached": true,
"cache_key": "a1b2c3d4e5...",
"cached_at": "2026-02-22T10:30:00.000Z",
"expires_at": "2026-02-23T10:30:00.000Z",
"content_type": "image/png"
}
/v1/usage
Get your current monthly usage and plan limits.
Response:
{
"plan": "growth",
"period": {
"start": "2026-02-01T00:00:00.000Z",
"end": "2026-02-28T23:59:59.000Z"
},
"usage": {
"screenshots_used": 1423,
"screenshots_limit": 10000,
"screenshots_remaining": 8577
}
}
/v1/usage/daily
Get daily usage breakdown. Useful for charts and usage monitoring.
| Param | Default | Description |
|---|---|---|
| days | 30 | Number of days to look back (1-90) |
Response:
{
"days": 30,
"data": [
{ "date": "2026-02-20", "count": 47 },
{ "date": "2026-02-21", "count": 83 },
{ "date": "2026-02-22", "count": 12 }
]
}
Parameters
All parameters are passed as query strings to GET /v1/screenshot. All features are available on every plan.
| Parameter | Type | Default | Description |
|---|---|---|---|
| url | string | — | URL to screenshot. Must be a public HTTP/HTTPS URL. required |
| format | string | png | Output format: png jpeg webp pdf |
| width | integer | 1280 | Viewport width in pixels. Range: 320–3840. |
| height | integer | 800 | Viewport height in pixels. Range: 200–10,000. |
| full_page | boolean | false | Capture the full scrollable page. Max height capped at 32,768px to prevent OOM. |
| quality | integer | 90 | Output quality for JPEG and WebP. Range: 1–100. Ignored for PNG/PDF. |
| delay | integer | 0 | Milliseconds to wait after page load before capture. Range: 0–10,000. Useful for pages with animations or lazy-loaded content. |
| dark_mode | boolean | false | Emulate prefers-color-scheme: dark. Works with sites that have dark mode CSS. |
| block_ads | boolean | true | Block ads and tracking scripts before capture. |
| block_cookie_banners | boolean | true | Remove cookie consent banners and GDPR dialogs. |
| hide_selectors | string | — | Comma-separated CSS selectors to hide (sets display:none). Example: .header,.footer,#banner |
| click_selector | string | — | CSS selector of an element to click before capture. Useful for dismissing modals or expanding content. |
| device | string | — | Device preset name. Sets viewport, pixel density, user agent, and mobile flag. See Device Presets. |
| user_agent | string | — | Custom User-Agent string. Overrides the default (or device preset) user agent. |
| cache | boolean | true | Use cached result if available. Set to false to force a fresh capture. |
| cache_ttl | integer | 86400 | Cache TTL in seconds. Range: 0–2,592,000 (30 days). Clamped to your plan's max. See Rate Limits. |
| response_type | string | binary | binary returns the image directly. json returns metadata + base64 data URI. See Response Format. |
true or false as string values in the query string.
Device Presets
Use the device parameter to emulate a real device. This sets viewport dimensions, pixel density, mobile mode, and user agent string automatically.
| Preset Name | Viewport | Scale | Mobile | User Agent |
|---|---|---|---|---|
| iphone_14 | 390 × 844 | 3x | Yes | iPhone; CPU iPhone OS 16_0 (Safari 604.1) |
| iphone_15_pro | 393 × 852 | 3x | Yes | iPhone; CPU iPhone OS 17_0 (Safari 604.1) |
| pixel_7 | 412 × 915 | 2.625x | Yes | Pixel 7; Android 13 (Chrome 116) |
| ipad_pro | 1024 × 1366 | 2x | Yes | iPad; CPU OS 16_0 (Safari 604.1) |
| macbook_pro | 1440 × 900 | 2x | No | Mac OS X 10_15_7 (Chrome 120) |
When using a device preset, the width, height, and user_agent parameters are overridden by the preset values.
Response Format
Binary response (default)
The screenshot image is returned directly as the response body with the appropriate Content-Type header (image/png, image/jpeg, image/webp, or application/pdf).
JSON response
Set response_type=json to get metadata and the image as a base64 data URI. Recommended for AI agents and workflows that need to process the image inline.
{
"url": "https://example.com",
"format": "png",
"width": 1280,
"height": 800,
"image": "data:image/png;base64,iVBORw0KGgo...",
"size": 248576,
"cache": "MISS",
"responseTime": "2847ms",
"remainingCredits": 8577
}
Response headers
All screenshot responses include these headers:
| Header | Description |
|---|---|
| X-Cache | HIT or MISS |
| X-Request-Id | Unique request ID for debugging |
| X-Response-Time | Time to generate the screenshot (e.g. 2847ms) |
| X-Remaining-Credits | Remaining screenshots for the current billing period |
| Content-Type | image/png, image/jpeg, image/webp, application/pdf, or application/json |
| Content-Length | Size in bytes (binary responses only) |
Error Handling
All API errors return JSON with a consistent structure:
{
"error": {
"code": "INVALID_URL",
"message": "The provided URL is not a valid HTTP/HTTPS URL.",
"status": 400
}
}
Error codes
| Code | HTTP | Description |
|---|---|---|
| UNAUTHORIZED | 401 | Missing or invalid API key |
| VALIDATION_ERROR | 400 | Invalid query parameters (Zod validation failed) |
| INVALID_URL | 400 | URL is not a valid HTTP or HTTPS URL |
| BLOCKED_URL | 400 | URL points to a private, local, or blocked address (SSRF protection) |
| INVALID_DEVICE | 400 | Unknown device preset name |
| RATE_LIMITED | 429 | Burst rate limit exceeded. Slow down and retry. |
| DOMAIN_RATE_LIMITED | 429 | Too many requests to the same domain (max 10/min) |
| QUOTA_EXCEEDED | 429 | Monthly quota reached. Upgrade your plan. |
| RENDER_TIMEOUT | 408 | Page took longer than 30 seconds to render |
| RENDER_FAILED | 502 | Chromium failed to render the page |
| OUTPUT_TOO_LARGE | 413 | Screenshot exceeds the 10MB size limit |
| SERVICE_UNAVAILABLE | 503 | Service temporarily unavailable |
| SERVER_ERROR | 500 | Internal server error |
For 429 responses, check the Retry-After header for the number of seconds to wait before retrying.
Rate Limits & Quotas
Each plan has a monthly screenshot quota and per-minute burst limit. All plans also have a per-domain rate limit of 10 requests per minute.
| Plan | Monthly Quota | Burst Rate | Domain Rate | Max Cache TTL | Price |
|---|---|---|---|---|---|
| Free | 500 | 5/min | 10/min | 1 day | $0 |
| Starter | 2,000 | 30/min | 10/min | 7 days | $9/mo |
| Growth | 10,000 | 60/min | 10/min | 30 days | $29/mo |
| Business | 50,000 | 120/min | 10/min | 30 days | $79/mo |
| Scale | 200,000 | 300/min | 10/min | 30 days | $199/mo |
Quotas reset on the 1st of each month (UTC). Cached responses (cache HIT) still count toward your monthly quota. Use the /v1/usage endpoint to monitor your usage programmatically.
Caching
Screenshots are cached on Cloudflare R2 for fast repeat access. Cache behavior is controlled by two parameters:
cache=true|false— Whether to use the cache. Default:true.cache_ttl=SECONDS— How long to store the cached result. Default: 86,400 (1 day). Clamped to your plan's max TTL.
The cache key is based on all screenshot parameters (URL, format, viewport, device, etc.), so changing any parameter generates a fresh screenshot.
Use the /v1/screenshot/info endpoint to check if a screenshot is cached without taking a new one.
Check the X-Cache response header: HIT means the result came from cache, MISS means a fresh capture was performed.
SDKs
Official client libraries for popular languages. The API is also a standard REST endpoint that works with any HTTP client.
Node.js
npm install snaprender
import SnapRender from 'snaprender';
import fs from 'node:fs';
const snap = new SnapRender({ apiKey: 'sk_live_your_key_here' });
// Capture as buffer
const buffer = await snap.capture({ url: 'https://example.com', format: 'png' });
fs.writeFileSync('screenshot.png', buffer);
// Capture with options
const result = await snap.capture({
url: 'https://github.com',
format: 'jpeg',
fullPage: true,
darkMode: true,
quality: 85,
device: 'iphone_15_pro',
});
fs.writeFileSync('github-mobile-dark.jpg', result);
// Check usage
const usage = await snap.usage();
console.log(`${usage.remaining} screenshots remaining`);
Python
pip install snaprender
from snaprender import SnapRender
snap = SnapRender("sk_live_your_key_here")
# Capture as bytes
data = snap.capture("https://example.com", format="png")
with open("screenshot.png", "wb") as f:
f.write(data)
# Capture with options
data = snap.capture(
"https://github.com",
format="jpeg",
full_page=True,
dark_mode=True,
quality=85,
device="iphone_15_pro",
)
with open("github-mobile-dark.jpg", "wb") as f:
f.write(data)
# Check usage
usage = snap.usage()
print(f"{usage['remaining']} screenshots remaining")
MCP Server
Connect SnapRender to Claude Desktop, Claude Code, Cursor, or any MCP-compatible AI tool. Two options:
Remote (no install required)
Add to your MCP client config (e.g. claude_desktop_config.json):
{
"mcpServers": {
"snaprender": {
"type": "streamable-http",
"url": "https://app.snap-render.com/mcp",
"headers": {
"Authorization": "Bearer sk_live_your_key_here"
}
}
}
}
Local (npm package)
Runs the MCP server locally via npx:
{
"mcpServers": {
"snaprender": {
"command": "npx",
"args": ["-y", "snaprender-mcp"],
"env": {
"SNAPRENDER_API_KEY": "sk_live_your_key_here"
}
}
}
}
Once connected, ask your AI assistant: "Take a screenshot of github.com" and it will call the SnapRender API through MCP.
Code Examples
Basic screenshot
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=png" \
-H "X-API-Key: YOUR_API_KEY" \
--output screenshot.png
Full page capture
curl "https://app.snap-render.com/v1/screenshot?url=https://en.wikipedia.org/wiki/Screenshot&format=png&full_page=true" \
-H "X-API-Key: YOUR_API_KEY" \
--output full-page.png
Dark mode
curl "https://app.snap-render.com/v1/screenshot?url=https://github.com&format=png&dark_mode=true" \
-H "X-API-Key: YOUR_API_KEY" \
--output github-dark.png
Device emulation
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&device=iphone_15_pro&format=png" \
-H "X-API-Key: YOUR_API_KEY" \
--output mobile.png
Hide elements
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=png&hide_selectors=.header,.footer,%23sidebar" \
-H "X-API-Key: YOUR_API_KEY" \
--output clean.png
PDF generation
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=pdf&full_page=true" \
-H "X-API-Key: YOUR_API_KEY" \
--output page.pdf
JSON response for AI agents
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=png&response_type=json" \
-H "X-API-Key: YOUR_API_KEY"
Returns a JSON object with the screenshot as a base64 data URI in the image field, plus metadata like size, cache status, and remaining credits.
Node.js (fetch, no SDK)
const url = new URL('https://app.snap-render.com/v1/screenshot');
url.searchParams.set('url', 'https://example.com');
url.searchParams.set('format', 'png');
url.searchParams.set('dark_mode', 'true');
const res = await fetch(url, {
headers: { 'X-API-Key': 'YOUR_API_KEY' },
});
const buffer = Buffer.from(await res.arrayBuffer());
fs.writeFileSync('screenshot.png', buffer);
console.log(`Cache: ${res.headers.get('x-cache')}, Remaining: ${res.headers.get('x-remaining-credits')}`);
Python (requests, no SDK)
import requests
response = requests.get(
"https://app.snap-render.com/v1/screenshot",
params={"url": "https://example.com", "format": "png", "dark_mode": "true"},
headers={"X-API-Key": "YOUR_API_KEY"},
)
response.raise_for_status()
with open("screenshot.png", "wb") as f:
f.write(response.content)
print(f"Cache: {response.headers['X-Cache']}, Remaining: {response.headers['X-Remaining-Credits']}")
Check usage
curl "https://app.snap-render.com/v1/usage" \
-H "X-API-Key: YOUR_API_KEY"
Ready to start?
Create a free account and get your API key in 30 seconds.