Screenshot & Snapshot

POST

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

Authentication

This endpoint requires API key authentication. Include your API key in the X-API-Key header:

X-API-Key: YOUR_API_KEY

Request Parameters

Required Parameters

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

ParameterTypeDefaultConstraintsDescription
devicestringdesktopmobile, tablet, desktopDevice preset for viewport and user agent. Overrides custom viewport settings.
viewportobjectdesktop preset-Custom viewport dimensions. Ignored if device is specified.
viewport.widthnumber1920Min: 320, Max: 3840Viewport width in pixels
viewport.heightnumber1080Min: 240, Max: 2160Viewport height in pixels
viewport.deviceScaleFactornumber1Min: 1, Max: 3Device pixel ratio (1=standard, 2=retina)

Optional Parameters - Capture Options

ParameterTypeDefaultDescription
fullPagebooleanfalseCapture the entire scrollable page instead of just the visible viewport. Note: Very tall pages (>16,384px) may fail due to browser rendering constraints.
selectorstring-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

ParameterTypeDefaultDescription
blockAdsbooleanfalseBlock ads and trackers using advanced pattern matching. Blocks common ad networks, tracking scripts, and analytics.
blockCookieBannersbooleanfalseAutomatically detect and remove cookie consent banners using heuristic matching. Works on both static and dynamically loaded banners.

Optional Parameters - Image Format

ParameterTypeDefaultConstraintsDescription
formatstringwebppng, jpeg, webpOutput image format. WebP offers best compression, PNG is lossless, JPEG is widely compatible.
qualitynumber | string80Number: 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).
omitBackgroundbooleanfalse-Make the background transparent (PNG only). Useful for capturing elements with transparent backgrounds.

Optional Parameters - Timing & Behavior

ParameterTypeDefaultConstraintsDescription
timeoutnumber30000Min: 1000, Max: 60000Navigation timeout in milliseconds. If page doesn't load within this time, request fails.
waitFornumber0Min: 0, Max: 10000Wait time in milliseconds after page load before capturing. Useful for letting animations complete or dynamic content load.
waitUntilstringnetworkidle2load, domcontentloaded, networkidle0, networkidle2When 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:

DeviceWidthHeightDPRUser Agent
mobile375px667px2iPhone iOS 14.7.1 Safari
tablet768px1024px2iPad iOS 14.7.1 Safari
desktop1920px1080px1WebPeekBot/1.0

Wait Conditions

Control when to capture the screenshot using the waitUntil parameter:

load

Wait for load event (fastest, but may miss dynamic content)

domcontentloaded

Wait for DOMContentLoaded event

networkidle0

Wait until no network connections for 500ms

networkidle2

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

FieldTypeDescription
urlstringThe original URL requested
screenshot_urlstringPublic URL to access the captured screenshot
widthnumberScreenshot width in pixels
heightnumberScreenshot height in pixels
formatstringImage format: png, jpeg, or webp
size_bytesnumberScreenshot file size in bytes
checksumstringSHA-256 checksum for integrity verification
cachedbooleanWhether this result was served from cache
cache_ttl_secondsnumberRemaining cache lifetime in seconds (default: 86400 = 24 hours)
viewportobjectViewport configuration used for capture
viewport.widthnumberViewport width in pixels
viewport.heightnumberViewport height in pixels
viewport.deviceScaleFactornumberDevice pixel ratio used
optionsobjectCapture options used
options.fullPagebooleanWhether full page was captured
options.blockAdsbooleanWhether ads were blocked
options.blockCookieBannersbooleanWhether cookie banners were blocked
options.selectorstring | nullCSS selector if element targeting was used
created_atstring (ISO 8601)Timestamp when screenshot was created
metadataobjectPerformance and processing metadata
metadata.processing_time_msnumberTotal request processing time
metadata.page_load_time_msnumberTime to load and render the page
metadata.requests_blockednumberNumber 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

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

snapshot.py
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

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

ScreenshotViewer.tsx
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