API Documentation
Everything you need to capture website screenshots programmatically.
Getting Started
Start capturing screenshots in three simple steps.
Create an account
Sign up for a free account. No credit card required.
Copy your API key
Go to your dashboard and copy your API key.
Make your first request
Use the example below to capture your first screenshot.
curl -X GET "https://api.fastscreenshotapi.com/v1/screenshot?url=https://example.com" \
-H "X-Api-Key: your_api_key" \
--output screenshot.pngAuthentication
All API requests require authentication. There are three ways to authenticate.
X-Api-Key header Recommended
Pass your API key via the X-Api-Key header.
curl "https://api.fastscreenshotapi.com/v1/screenshot?url=https://example.com" \
-H "X-Api-Key: fsa_your_api_key"Query parameter
Pass your API key as an api_key query parameter. Useful for embedding in <img> tags.
<img src="https://api.fastscreenshotapi.com/v1/screenshot?url=https://example.com&api_key=fsa_your_api_key" />Bearer token
For dashboard API endpoints, use a Bearer token in the Authorization header.
curl "https://api.fastscreenshotapi.com/v1/account" \
-H "Authorization: Bearer your_access_token"Screenshot Endpoint
GET /v1/screenshot
Pass parameters as query strings. Ideal for embedding in <img> tags.
curl "https://api.fastscreenshotapi.com/v1/screenshot?url=https://example.com&format=webp&full_page=true" \
-H "X-Api-Key: fsa_your_api_key" \
--output screenshot.webpPOST /v1/screenshot
Send parameters as a JSON body for full control over all options.
curl -X POST "https://api.fastscreenshotapi.com/v1/screenshot" \
-H "X-Api-Key: fsa_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "webp",
"full_page": true,
"viewport_width": 1440,
"dark_mode": true
}' \
--output screenshot.webpParameters
All parameters for the screenshot endpoint.
| Parameter | Type | Default | Plan | Description |
|---|---|---|---|---|
url | string | required | Free | URL to capture |
format | string | png | Free | Output format: png, jpeg, webp |
quality | integer | 85 | Free | Image quality for JPEG/WebP (1-100) |
full_page | boolean | false | Free | Capture entire scrollable page |
mobile | boolean | false | Free | Use mobile viewport and user agent |
block_cookie_banners | boolean | true | Free | Auto-dismiss cookie/GDPR banners |
block_ads | boolean | false | Free | Block ad scripts |
scroll_to_bottom | boolean | true | Free | Auto-scroll for lazy-loaded content |
delay | integer | 0 | Free | Extra delay after page load in ms (0-10000) |
wait_for_timeout | integer | 30000 | Free | Max wait time in ms (1000-60000) |
cache_ttl | integer | 86400 | Free | Cache duration in seconds (0 = no cache, max 604800) |
response_type | string | binary | Free | Response format: binary, json, url |
viewport_width | integer | 1920 | Starter+ | Browser viewport width (320-3840) |
viewport_height | integer | 1080 | Starter+ | Browser viewport height (240-2160) |
device_scale_factor | float | 1 | Starter+ | Pixel density (2 for Retina) |
custom_css | string | — | Starter+ | CSS to inject before capture (max 5000 chars) |
hide_selectors | array | [] | Starter+ | CSS selectors to hide (max 10) |
dark_mode | boolean | false | Pro+ | Prefer dark color scheme |
custom_headers | object | — | Pro+ | Custom HTTP headers to send (max 10) |
cookies | array | — | Pro+ | Cookies to set: [{name, value, domain}] |
html | string | — | Pro+ | HTML to render instead of URL (max 1MB, POST only) |
webhook_url | string | — | Pro+ | URL for async result delivery (async endpoint only) |
webhook_secret | string | — | Pro+ | HMAC-SHA256 secret for webhook signature verification |
upload_to | object | — | Pro+ | External S3/R2 storage config (async endpoint only) |
Response Types
Control the response format with the response_type parameter.
binary (default)
Returns raw image data with the appropriate Content-Type header (image/png, image/jpeg, or image/webp).
json
Returns a JSON object with a base64-encoded screenshot and metadata.
{
"data": {
"screenshot": "iVBORw0KGgoAAAANSUhEUgAA...",
"format": "png",
"width": 1920,
"height": 1080,
"file_size": 284729
},
"metadata": {
"url": "https://example.com",
"title": "Example Domain",
"request_id": "req_abc123",
"cached": false,
"duration_ms": 1240
}
}url
Returns a JSON object with a temporary URL to the screenshot (valid for 1 hour).
{
"data": {
"url": "https://api.fastscreenshotapi.com/screenshots/req_abc123.png?expires=1700000000&sig=...",
"format": "png",
"width": 1920,
"height": 1080,
"file_size": 284729,
"expires_at": "2024-11-15T12:00:00Z"
},
"metadata": {
"url": "https://example.com",
"title": "Example Domain",
"request_id": "req_abc123",
"cached": false,
"duration_ms": 1240
}
}Response Headers
Every response includes these headers with request metadata.
| Header | Description |
|---|---|
X-Request-Id | Unique request identifier for debugging and support |
X-RateLimit-Limit | Maximum requests allowed per minute |
X-RateLimit-Remaining | Remaining requests in the current minute window |
X-RateLimit-Reset | Unix timestamp when the rate limit resets |
X-Quota-Limit | Total monthly screenshot quota for your plan |
X-Quota-Used | Screenshots used in the current billing period |
X-Cache | Cache status: HIT (served from cache) or MISS (fresh capture) |
Caching
Screenshots are cached to improve performance and reduce redundant captures.
- Default cache duration is 24 hours (86400 seconds).
- Same URL + same parameters = instant cache hit (~300ms response time).
- Cached requests do not count against your monthly quota.
- Use
cache_ttl=0to disable caching. Maximum TTL is 7 days (604800 seconds).
Anti-bot Bypass
Many websites use bot detection (Cloudflare, DataDome, PerimeterX) that blocks headless browsers. On Pro+ plans, FastScreenshotAPI automatically uses stealth mode with ISP residential proxies to bypass these protections.
- Stealth browser fingerprinting — mimics real user browsers.
- ISP residential proxies — real IP addresses, not datacenter IPs.
- Automatic — no extra parameters needed. Just works on Pro and Business plans.
Plan Requirements
Some features require a specific plan. If you use a restricted feature on a lower plan, the API returns a 403 FEATURE_RESTRICTED error.
| Plan | Features Included |
|---|---|
| Free | Core parameters: url, format, quality, full_page, mobile, block_cookie_banners, block_ads, scroll_to_bottom, delay, cache_ttl, response_type |
| Starter+ | + viewport_width, viewport_height, device_scale_factor, custom_css, hide_selectors |
| Pro+ | + dark_mode, custom_headers, cookies, html, webhook_url, webhook_secret, upload_to, anti-bot bypass, async endpoint |
| Business | + Priority rendering queue |
Code Examples
Complete, copy-pasteable examples in popular languages.
curl -X POST "https://api.fastscreenshotapi.com/v1/screenshot" \
-H "X-Api-Key: fsa_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "webp",
"quality": 90,
"full_page": true,
"viewport_width": 1440,
"block_cookie_banners": true
}' \
--output screenshot.webpconst response = await fetch("https://api.fastscreenshotapi.com/v1/screenshot", {
method: "POST",
headers: {
"X-Api-Key": "fsa_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com",
format: "webp",
quality: 90,
full_page: true,
viewport_width: 1440,
block_cookie_banners: true,
}),
});
const buffer = await response.arrayBuffer();
const fs = await import("fs");
fs.writeFileSync("screenshot.webp", Buffer.from(buffer));
console.log("Request ID:", response.headers.get("X-Request-Id"));
console.log("Cached:", response.headers.get("X-Cache"));import requests
response = requests.post(
"https://api.fastscreenshotapi.com/v1/screenshot",
headers={"X-Api-Key": "fsa_your_api_key"},
json={
"url": "https://example.com",
"format": "webp",
"quality": 90,
"full_page": True,
"viewport_width": 1440,
"block_cookie_banners": True,
},
)
with open("screenshot.webp", "wb") as f:
f.write(response.content)
print("Request ID:", response.headers["X-Request-Id"])
print("Cached:", response.headers["X-Cache"])$ch = curl_init("https://api.fastscreenshotapi.com/v1/screenshot");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: fsa_your_api_key",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"url" => "https://example.com",
"format" => "webp",
"quality" => 90,
"full_page" => true,
"viewport_width" => 1440,
"block_cookie_banners" => true,
]),
]);
$response = curl_exec($ch);
curl_close($ch);
file_put_contents("screenshot.webp", $response);<!-- Direct embedding — uses your API key as a query parameter -->
<img
src="https://api.fastscreenshotapi.com/v1/screenshot?url=https://example.com&format=webp&viewport_width=1440&api_key=fsa_your_api_key"
alt="Screenshot of example.com"
loading="lazy"
/>Async Screenshots
Use async screenshots for heavy pages, batch processing, serverless environments, or when you need webhook notifications.
POST /v1/screenshot/async
Submit a screenshot job and receive a job ID. The screenshot will be processed in the background.
curl -X POST https://api.fastscreenshotapi.com/v1/screenshot/async \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "png",
"full_page": true,
"webhook_url": "https://your-server.com/webhook",
"webhook_secret": "your-hmac-secret"
}'Response (202)
{
"job_id": "job_cZ1DADXGyzNM",
"status": "queued",
"status_url": "https://api.fastscreenshotapi.com/v1/screenshot/status/job_cZ1DADXGyzNM",
"estimated_time_ms": 30000
}Checking Status
Use GET /v1/screenshot/status/{jobId} to check the status of a job. A job can be in one of three statuses:
- queued — the job is waiting to be picked up by a worker.
- processing — the browser is loading the page and capturing the screenshot.
- completed / failed — the job finished successfully or encountered an error.
Polling vs Webhooks
For production use, we recommend webhooks — they deliver results instantly without repeated API calls. Use polling only for testing or when webhooks are not feasible.
Webhook Verification
Webhooks are signed with HMAC-SHA256. The signature is sent in the X-Webhook-Signature header. Always verify the signature before processing webhook payloads.
const crypto = require('crypto');
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const expected = crypto
.createHmac('sha256', 'your-webhook-secret')
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expected) {
return res.status(401).send('Invalid signature');
}
const { job_id, status, screenshot_url } = req.body;
console.log(`Job ${job_id}: ${status}`);
res.status(200).send('OK');
});import hmac, hashlib
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Webhook-Signature')
expected = hmac.new(
b'your-webhook-secret',
request.data,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
abort(401)
data = request.json
print(f"Job {data['job_id']}: {data['status']}")
return 'OK', 200HTML Rendering
Render custom HTML as a screenshot — perfect for invoices, OG images, email templates, and reports.
- Only available via POST (not GET).
htmlandurlare mutually exclusive — provide one or the other.- Maximum HTML size: 1 MB.
- Works with all
response_typeoptions (binary, json, url). - Runs in an isolated browser context for security.
curl -X POST https://api.fastscreenshotapi.com/v1/screenshot \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<html><body><h1>Invoice #123</h1><p>Total: $500</p></body></html>",
"format": "png",
"response_type": "json"
}'External Storage Upload
Upload screenshots directly to your own S3-compatible bucket instead of using our temporary storage.
- Supported providers: AWS S3, Cloudflare R2, DigitalOcean Spaces, Backblaze B2, MinIO, Wasabi.
- Minimum permissions:
s3:PutObject,s3:PutObjectAcl. - Available with async screenshots.
curl -X POST https://api.fastscreenshotapi.com/v1/screenshot/async \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"upload_to": {
"type": "s3",
"bucket": "my-screenshots",
"region": "eu-west-1",
"access_key": "AKIA...",
"secret_key": "...",
"path": "screenshots/"
}
}'For one-time bucket configuration, visit your dashboard storage settings.
Error Codes
When a request fails, the API returns a JSON error response with a machine-readable code, a human-readable message, and a suggestion to help you resolve the issue.
| Code | HTTP Status | Description | Suggestion |
|---|---|---|---|
INVALID_URL | 400 | URL is malformed or unreachable | Provide a valid URL starting with http:// or https:// |
INVALID_PARAMS | 400 | Validation error | Check parameter values against docs |
UNAUTHORIZED | 401 | Missing or invalid API key | Pass API key via X-Api-Key header |
ACCOUNT_SUSPENDED | 403 | Account suspended | Contact support |
PRIVATE_IP | 403 | URL resolves to private IP | Only publicly accessible URLs allowed |
FEATURE_RESTRICTED | 403 | Feature not available on your plan | Upgrade to a higher plan to access this feature |
QUOTA_EXCEEDED | 429 | Monthly quota reached | Upgrade plan for more screenshots |
RATE_LIMITED | 429 | Too many requests per minute | Wait and retry, check X-RateLimit-Reset header |
PAGE_NOT_FOUND | 422 | Target URL returned 404 | Check if the URL is correct |
SSL_ERROR | 422 | Target has SSL issues | Check target site's SSL certificate |
BLOCKED_BY_SITE | 422 | Target blocked the request | Site has bot protection |
SCREENSHOT_TIMEOUT | 504 | Page load timeout | Increase wait_for_timeout or simplify the target page |
SCREENSHOT_FAILED | 502 | Capture failed | Retry the request |
SERVICE_OVERLOADED | 503 | All containers busy | Retry with exponential backoff |
INTERNAL_ERROR | 500 | Server error | Contact support |
Error Response Format
Every error response follows the same structure:
{
"error": true,
"code": "SCREENSHOT_TIMEOUT",
"message": "Page did not finish loading within the timeout.",
"suggestion": "Try increasing wait_for_timeout or use wait_for: 'domcontentloaded'.",
"documentation_url": "https://fastscreenshotapi.com/docs#error-codes"
}