Screenshot & Snapshot
The Snapshot endpoint captures high-quality screenshots of any public web page with advanced features including viewport control, device emulation, full-page capture, element targeting, ad blocking, and cookie banner removal. Perfect for creating visual previews, monitoring visual changes, or capturing page states.
Endpoint
POST /snapshotAuthentication
This endpoint requires API key authentication. Include your API key in the X-API-Key header:
X-API-Key: YOUR_API_KEYRequest Parameters
Required Parameters
| Parameter | Type | Description |
|---|---|---|
| url | string | The public URL to capture. Must be a valid HTTP/HTTPS URL. Cannot be localhost, private IPs, or internal domains (SSRF protection). |
Optional Parameters - Viewport Configuration
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
| device | string | desktop | mobile, tablet, desktop | Device preset for viewport and user agent. Overrides custom viewport settings. |
| viewport | object | desktop preset | - | Custom viewport dimensions. Ignored if device is specified. |
| viewport.width | number | 1920 | Min: 320, Max: 3840 | Viewport width in pixels |
| viewport.height | number | 1080 | Min: 240, Max: 2160 | Viewport height in pixels |
| viewport.deviceScaleFactor | number | 1 | Min: 1, Max: 3 | Device pixel ratio (1=standard, 2=retina) |
Optional Parameters - Capture Options
| Parameter | Type | Default | Description |
|---|---|---|---|
| fullPage | boolean | false | Capture the entire scrollable page instead of just the visible viewport. Note: Very tall pages (>16,384px) may fail due to browser rendering constraints. |
| selector | string | - | CSS selector to capture a specific element instead of the full page. Element will be scrolled into view and centered before capture. |
Optional Parameters - Content Blocking
| Parameter | Type | Default | Description |
|---|---|---|---|
| blockAds | boolean | false | Block ads and trackers using advanced pattern matching. Blocks common ad networks, tracking scripts, and analytics. |
| blockCookieBanners | boolean | false | Automatically detect and remove cookie consent banners using heuristic matching. Works on both static and dynamically loaded banners. |
Optional Parameters - Image Format
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
| format | string | webp | png, jpeg, webp | Output image format. WebP offers best compression, PNG is lossless, JPEG is widely compatible. |
| quality | number | string | 80 | Number: 0-100 String: low, medium, high | Image quality. Number sets exact quality (0-100). Presets: low=60, medium=80, high=95. Ignored for PNG (lossless). |
| omitBackground | boolean | false | - | Make the background transparent (PNG only). Useful for capturing elements with transparent backgrounds. |
Optional Parameters - Timing & Behavior
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
| timeout | number | 30000 | Min: 1000, Max: 60000 | Navigation timeout in milliseconds. If page doesn't load within this time, request fails. |
| waitFor | number | 0 | Min: 0, Max: 10000 | Wait time in milliseconds after page load before capturing. Useful for letting animations complete or dynamic content load. |
| waitUntil | string | networkidle2 | load, domcontentloaded, networkidle0, networkidle2 | When to consider navigation complete: load (Window load event), domcontentloaded (DOMContentLoaded event), networkidle0 (No network activity for 500ms), networkidle2 (Max 2 network connections for 500ms) |
Device Presets
The API provides three device presets with optimized viewport dimensions and user agents:
| Device | Width | Height | DPR | User Agent |
|---|---|---|---|---|
| mobile | 375px | 667px | 2 | iPhone iOS 14.7.1 Safari |
| tablet | 768px | 1024px | 2 | iPad iOS 14.7.1 Safari |
| desktop | 1920px | 1080px | 1 | WebPeekBot/1.0 |
Wait Conditions
Control when to capture the screenshot using the waitUntil parameter:
Wait for load event (fastest, but may miss dynamic content)
Wait for DOMContentLoaded event
Wait until no network connections for 500ms
Wait until ≤2 network connections for 500ms (default, recommended)
Example Requests
Basic Screenshot
curl -X POST "https://api.webpeek.dev/snapshot" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com"
}'Full Page Screenshot
curl -X POST "https://api.webpeek.dev/snapshot" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com",
"fullPage": true
}'Mobile Screenshot
curl -X POST "https://api.webpeek.dev/snapshot" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com",
"device": "mobile"
}'Custom Viewport with Retina Display
curl -X POST "https://api.webpeek.dev/snapshot" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com",
"viewport": {
"width": 1920,
"height": 1080,
"deviceScaleFactor": 2
}
}'WebP with Custom Quality
curl -X POST "https://api.webpeek.dev/snapshot" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com",
"format": "webp",
"quality": 90
}'Complete Configuration Example
curl -X POST "https://api.webpeek.dev/snapshot" \
-H "Content-Type: application/json" \
-d '{
"url": "https://webpeek.dev",
"viewport": {
"width": 1920,
"height": 1080,
"deviceScaleFactor": 1
},
"device": "desktop",
"fullPage": true,
"blockAds": true,
"blockCookieBanners": true,
"format": "webp",
"quality": 80,
"timeout": 30000,
"waitFor": 1000,
"waitUntil": "networkidle2",
"omitBackground": false
}'Response Format
Success Response (200 OK)
{
"url": "https://example.com",
"screenshot_url": "https://storage.example.com/screenshots/abc123.webp",
"width": 1920,
"height": 1080,
"format": "webp",
"size_bytes": 145234,
"checksum": "abc123def456789",
"cached": false,
"cache_ttl_seconds": 86400,
"viewport": {
"width": 1920,
"height": 1080,
"deviceScaleFactor": 1
},
"options": {
"fullPage": false,
"blockAds": true,
"blockCookieBanners": true,
"selector": null
},
"created_at": "2025-01-06T12:00:00.000Z",
"metadata": {
"processing_time_ms": 3245,
"page_load_time_ms": 2890,
"requests_blocked": 23
}
}Response Fields Reference
| Field | Type | Description |
|---|---|---|
| url | string | The original URL requested |
| screenshot_url | string | Public URL to access the captured screenshot |
| width | number | Screenshot width in pixels |
| height | number | Screenshot height in pixels |
| format | string | Image format: png, jpeg, or webp |
| size_bytes | number | Screenshot file size in bytes |
| checksum | string | SHA-256 checksum for integrity verification |
| cached | boolean | Whether this result was served from cache |
| cache_ttl_seconds | number | Remaining cache lifetime in seconds (default: 86400 = 24 hours) |
| viewport | object | Viewport configuration used for capture |
| viewport.width | number | Viewport width in pixels |
| viewport.height | number | Viewport height in pixels |
| viewport.deviceScaleFactor | number | Device pixel ratio used |
| options | object | Capture options used |
| options.fullPage | boolean | Whether full page was captured |
| options.blockAds | boolean | Whether ads were blocked |
| options.blockCookieBanners | boolean | Whether cookie banners were blocked |
| options.selector | string | null | CSS selector if element targeting was used |
| created_at | string (ISO 8601) | Timestamp when screenshot was created |
| metadata | object | Performance and processing metadata |
| metadata.processing_time_ms | number | Total request processing time |
| metadata.page_load_time_ms | number | Time to load and render the page |
| metadata.requests_blocked | number | Number of requests blocked (ads, trackers) |
Error Responses
400 Bad Request - Validation Error
Returned when request parameters are invalid.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"http_status": 400,
"details": [
{
"code": "invalid_type",
"expected": "string",
"received": "number",
"path": ["url"],
"message": "Expected string, received number"
}
]
}
}Common causes: Invalid URL format, URL violates SSRF protection (localhost, private IPs), viewport dimensions out of range, invalid device value, invalid format or quality value, timeout values out of range.
404 Not Found - Element Not Found
Returned when the specified CSS selector doesn't match any element.
{
"error": {
"code": "ELEMENT_NOT_FOUND",
"message": "Selector \"#non-existent-element\" not found",
"http_status": 404
}
}408 Request Timeout
Returned when page navigation exceeds the timeout limit.
{
"error": {
"code": "TIMEOUT",
"message": "Navigation timeout exceeded 30000ms",
"http_status": 408
}
}413 Payload Too Large - Page Too Tall
Returned when attempting to capture a full page that exceeds browser rendering limits.
{
"error": {
"code": "PAGE_TOO_TALL",
"message": "Failed to capture 18500px tall page (1920px wide) due to browser rendering constraints. Chrome cannot render pages exceeding ~16,384px in certain dimensions. Try using 'selector' to capture specific elements instead of fullPage, or reduce viewport width.",
"http_status": 413
}
}Solution: Use selector to capture specific elements, or reduce viewport width, or set fullPage: false to capture only the visible viewport.
Use Cases
- Website monitoring and change detection
- Social media preview images
- PDF report generation with screenshots
- Automated visual regression testing
- Website portfolio galleries
- Competitive analysis and tracking
- Website archiving and documentation
- Thumbnail generation for search results
Code Examples
Here's how to use the snapshot endpoint in different languages:
JavaScript / Node.js
async function captureScreenshot(url, options = {}) {
const response = await fetch('https://api.webpeek.dev/snapshot', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
url,
...options
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
}
// Example 1: Basic screenshot
const screenshot = await captureScreenshot('https://github.com', {
fullPage: true,
format: 'png'
});
console.log('Screenshot URL:', screenshot.screenshot_url);
console.log('Size:', screenshot.size_bytes, 'bytes');
console.log('Dimensions:', `${screenshot.width}x${screenshot.height}`);
console.log('Created at:', screenshot.created_at);
// Example 2: Download screenshot from URL (Node.js)
const fs = require('fs');
const https = require('https');
const file = fs.createWriteStream('screenshot.png');
https.get(screenshot.screenshot_url, (response) => {
response.pipe(file);
file.on('finish', () => {
file.close();
console.log('Screenshot downloaded successfully');
});
});
// Example 3: High-quality retina screenshot
const retinaScreenshot = await captureScreenshot('https://github.com', {
viewport: {
width: 1920,
height: 1080,
deviceScaleFactor: 2
},
format: 'webp',
quality: 90,
waitUntil: 'networkidle2'
});Python
import requests
import base64
from pathlib import Path
def capture_screenshot(url, **options):
payload = {'url': url, **options}
response = requests.post(
'https://api.webpeek.dev/snapshot',
json=payload
)
response.raise_for_status()
return response.json()
def save_screenshot(url, filename, **options):
# Get screenshot data
data = capture_screenshot(url, **options)
# Download screenshot from URL
import urllib.request
urllib.request.urlretrieve(data['screenshot_url'], filename)
print(f"Screenshot saved to {filename}")
print(f"URL: {data['screenshot_url']}")
print(f"Size: {data['size_bytes']} bytes")
print(f"Dimensions: {data['width']}x{data['height']}")
print(f"Format: {data['format']}")
return data
# Example 1: Full page screenshot
screenshot = save_screenshot(
'https://github.com',
'screenshot.png',
fullPage=True,
format='png'
)
# Example 2: Mobile screenshot
mobile_screenshot = save_screenshot(
'https://github.com',
'mobile-screenshot.png',
device='mobile'
)
# Example 3: High-quality WebP with custom viewport
webp_screenshot = save_screenshot(
'https://github.com',
'screenshot.webp',
viewport={
'width': 1920,
'height': 1080,
'deviceScaleFactor': 2
},
format='webp',
quality=90,
waitUntil='networkidle2'
)PHP
<?php
function captureScreenshot($url, $options = []) {
$payload = array_merge(['url' => $url], $options);
$ch = curl_init('https://api.webpeek.dev/snapshot');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception("HTTP error: $httpCode");
}
$data = json_decode($response, true);
if ($data === null) {
throw new Exception('Failed to decode JSON response');
}
return $data;
}
function saveScreenshot($url, $filename, $options = []) {
$data = captureScreenshot($url, $options);
// Download screenshot from URL
$imageData = file_get_contents($data['screenshot_url']);
file_put_contents($filename, $imageData);
echo "Screenshot saved to $filename\n";
echo "URL: {$data['screenshot_url']}\n";
echo "Size: {$data['size_bytes']} bytes\n";
echo "Dimensions: {$data['width']}x{$data['height']}\n";
echo "Format: {$data['format']}\n";
return $data;
}
// Example 1: Full page screenshot
$screenshot = saveScreenshot(
'https://github.com',
'screenshot.png',
['fullPage' => true, 'format' => 'png']
);
// Example 2: Mobile screenshot
$mobileScreenshot = saveScreenshot(
'https://github.com',
'mobile-screenshot.png',
['device' => 'mobile']
);
// Example 3: High-quality WebP with custom viewport
$webpScreenshot = saveScreenshot(
'https://github.com',
'screenshot.webp',
[
'viewport' => [
'width' => 1920,
'height' => 1080,
'deviceScaleFactor' => 2
],
'format' => 'webp',
'quality' => 90,
'waitUntil' => 'networkidle2'
]
);
?>React Component Example
import { useState } from 'react';
interface ScreenshotData {
screenshot_url: string;
size_bytes: number;
width: number;
height: number;
format: string;
created_at: string;
}
export function ScreenshotViewer() {
const [url, setUrl] = useState('');
const [loading, setLoading] = useState(false);
const [screenshot, setScreenshot] = useState<ScreenshotData | null>(null);
const [error, setError] = useState<string | null>(null);
const captureScreenshot = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch('https://api.webpeek.dev/snapshot', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
url,
fullPage: false,
format: 'png',
})
});
if (!response.ok) {
throw new Error('Failed to capture screenshot');
}
const data = await response.json();
setScreenshot(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
};
return (
<div className="space-y-4">
<div className="flex gap-2">
<input
type="url"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="Enter URL..."
className="flex-1 px-4 py-2 border rounded"
/>
<button
onClick={captureScreenshot}
disabled={loading || !url}
className="px-6 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
>
{loading ? 'Capturing...' : 'Capture'}
</button>
</div>
{error && (
<div className="p-4 bg-red-100 text-red-700 rounded">
{error}
</div>
)}
{screenshot && (
<div className="space-y-2">
<img
src={screenshot.screenshot_url}
alt="Screenshot"
className="w-full border rounded shadow-lg"
/>
<div className="text-sm text-gray-600">
<p>Size: {(screenshot.size_bytes / 1024).toFixed(2)} KB</p>
<p>
Dimensions: {screenshot.width}x{screenshot.height}
</p>
<p>Format: {screenshot.format}</p>
<p>Captured: {new Date(screenshot.created_at).toLocaleString()}</p>
</div>
</div>
)}
</div>
);
}Best Practices
Use Appropriate Wait Conditions
For static sites, use waitUntil=load for faster captures. For dynamic sites with AJAX, use networkidle2 (default) to ensure content is loaded. Add a waitFor parameter if needed for animations.
Choose the Right Format
Use PNG for pixel-perfect quality and transparency support. Use JPEG or WebP with quality 70-80 for smaller file sizes when transparency is not needed. WebP provides the best compression.
Optimize Full Page Captures
Full page screenshots can be very large for long pages. Consider using JPEG/WebP format with quality=70 to reduce file size when capturing full pages with fullPage=true.
Use CDN URLs Directly
The screenshot_url field provides a direct CDN link to the screenshot. This is the most efficient way to access screenshots - use it directly in img tags or download it programmatically.
Enable Blockers for Cleaner Captures
Keep blockAds and blockCookieBanners enabled (default) for cleaner screenshots without distracting popups. Disable only when you need to capture the page exactly as users see it.
Test Different Devices
Capture screenshots for desktop, tablet, and mobile to ensure responsive designs look good across all devices. Mobile screenshots are especially important for mobile-first websites.
Leverage Retina/HiDPI Support
Set viewport.deviceScaleFactor=2 for high-resolution retina screenshots. This doubles the pixel density for crisp, high-quality images perfect for presentations and marketing materials.
Caching
Screenshots are cached for 24 hours (86400 seconds) by default based on URL and parameters. This improves performance and reduces costs for repeated requests. The response includes caching information:
- cached - Boolean indicating whether this response was served from cache
- cache_ttl_seconds - Cache time-to-live in seconds (default: 86400)
- created_at - ISO 8601 timestamp when the screenshot was captured
- checksum - SHA-256 checksum for verifying screenshot integrity
Cached screenshots are served instantly without re-rendering. The same screenshot URL will be returned for identical requests within the cache TTL period.
Rate Limiting
The snapshot endpoint is subject to rate limiting based on your subscription plan:
- Free tier: 50 snapshots/day
- Pro tier: 5,000 snapshots/day
- Enterprise tier: Custom limits
Rate limit information is included in response headers:
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4823
X-RateLimit-Reset: 1704537600