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
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

GET /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.

GET /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"
}
GET /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
  }
}
GET /v1/usage/daily

Get daily usage breakdown. Useful for charts and usage monitoring.

ParamDefaultDescription
days30Number 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.
Boolean parameters accept 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-CacheHIT or MISS
X-Request-IdUnique request ID for debugging
X-Response-TimeTime to generate the screenshot (e.g. 2847ms)
X-Remaining-CreditsRemaining screenshots for the current billing period
Content-Typeimage/png, image/jpeg, image/webp, application/pdf, or application/json
Content-LengthSize 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
UNAUTHORIZED401Missing or invalid API key
VALIDATION_ERROR400Invalid query parameters (Zod validation failed)
INVALID_URL400URL is not a valid HTTP or HTTPS URL
BLOCKED_URL400URL points to a private, local, or blocked address (SSRF protection)
INVALID_DEVICE400Unknown device preset name
RATE_LIMITED429Burst rate limit exceeded. Slow down and retry.
DOMAIN_RATE_LIMITED429Too many requests to the same domain (max 10/min)
QUOTA_EXCEEDED429Monthly quota reached. Upgrade your plan.
RENDER_TIMEOUT408Page took longer than 30 seconds to render
RENDER_FAILED502Chromium failed to render the page
OUTPUT_TOO_LARGE413Screenshot exceeds the 10MB size limit
SERVICE_UNAVAILABLE503Service temporarily unavailable
SERVER_ERROR500Internal 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
Free5005/min10/min1 day$0
Starter2,00030/min10/min7 days$9/mo
Growth10,00060/min10/min30 days$29/mo
Business50,000120/min10/min30 days$79/mo
Scale200,000300/min10/min30 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`);

View on npm

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")

View on PyPI

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.

View on npm

Code Examples

Basic screenshot

cURL
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
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
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
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
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
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
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)

JavaScript
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)

Python
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
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.