PageShot API

A powerful, developer-friendly API for capturing screenshots of any webpage. Built on Chromium for pixel-perfect accuracy, completely free with no API key required.

Base URL: https://pageshot.info/v1

Get Started

PageShot is completely free. No API key required. Just send a request with a URL and get your screenshot.

Quickstart

Take your first screenshot in under 30 seconds:

# Just pass a URL — no API key needed
curl "https://pageshot.info/v1/screenshot?url=https://example.com" \
  --output screenshot.png

# That's it! Open screenshot.png to see the result.

Authentication

PageShot is completely free and requires no authentication. Simply make a request to any endpoint.

GET /v1/screenshot

GET /v1/screenshot?url=https://example.com

Returns a screenshot image directly. Ideal for embedding in <img> tags or downloading.

Example Request

GET /v1/screenshot?url=https://example.com&width=1920&height=1080&format=png&dark_mode=true

Response Headers

HeaderDescription
X-Screenshot-TimeCapture duration (e.g., 2341ms)
Content-Typeimage/png, image/jpeg, or image/webp

POST /v1/screenshot

POST /v1/screenshot

More flexible screenshot capture. Supports JSON body and optional JSON response with base64 image.

Request Body (JSON)

{
  "url": "https://example.com",
  "width": 1920,
  "height": 1080,
  "full_page": true,
  "format": "png",
  "dark_mode": true,
  "block_ads": true,
  "css": "header { display: none !important; }",
  "selector": ".main-content",
  "delay": 2000,
  "response": "json"
}

JSON Response (when response=json)

{
  "success": true,
  "data": {
    "url": "https://example.com",
    "image": "data:image/png;base64,iVBORw0KGgo...",
    "format": "png",
    "width": 1920,
    "height": 1080,
    "size": 245632,
    "captureTime": "2341ms"
  }
}

GET /v1/status

GET /v1/status

Check API operational status. No authentication required.

{
  "status": "operational",
  "service": "PageShot API",
  "version": "2.0.0",
  "uptime": 86400.123,
  "timestamp": "2026-02-12T12:00:00.000Z"
}

Parameters Reference

ParameterTypeDefaultDescription
urlstringrequiredThe webpage URL to capture
widthinteger1280Viewport width (320-3840)
heightinteger720Viewport height (200-2160)
full_pagebooleanfalseCapture entire scrollable page
formatstringpngOutput: png, jpeg, webp
qualityinteger80JPEG/WebP quality (1-100)
dark_modebooleanfalseForce dark color scheme
block_adsbooleanfalseBlock ads and trackers
delayinteger0Wait before capture (ms, max 10000)
device_scalefloat1Device scale factor (0.5-3)
selectorstringnullCSS selector for element capture
cssstringnullCustom CSS to inject
user_agentstringnullCustom User-Agent string
timeoutinteger30000Page load timeout (ms, 5000-60000)
responsestringbinarySet to json for base64 response

Code Examples

Node.js / JavaScript

// Using fetch (Node 18+) — no API key needed
const response = await fetch('https://pageshot.info/v1/screenshot', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    url: 'https://example.com',
    width: 1280,
    height: 720,
    format: 'png'
  })
});

const buffer = Buffer.from(await response.arrayBuffer());
require('fs').writeFileSync('screenshot.png', buffer);
console.log(`Captured in ${response.headers.get('X-Screenshot-Time')}`);

Python

import requests

# No API key needed — just send the request
response = requests.post(
    'https://pageshot.info/v1/screenshot',
    json={
        'url': 'https://example.com',
        'width': 1280,
        'height': 720,
        'full_page': True,
        'format': 'png'
    }
)

with open('screenshot.png', 'wb') as f:
    f.write(response.content)

print(f"Captured in {response.headers['X-Screenshot-Time']}")

C# / .NET

// No API key needed
using var client = new HttpClient();

var payload = new {
    url = "https://example.com",
    width = 1920,
    height = 1080,
    full_page = true,
    dark_mode = true
};

var response = await client.PostAsJsonAsync(
    "https://pageshot.info/v1/screenshot", payload);

var bytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("screenshot.png", bytes);

PHP

// No API key needed
$ch = curl_init('https://pageshot.info/v1/screenshot');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json'
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'url' => 'https://example.com',
        'width' => 1920,
        'height' => 1080,
        'format' => 'png'
    ])
]);

$image = curl_exec($ch);
curl_close($ch);
file_put_contents('screenshot.png', $image);

Go

// No API key needed
payload := map[string]any{
    "url":    "https://example.com",
    "width":  1920,
    "height": 1080,
    "format": "png",
}

body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://pageshot.info/v1/screenshot",
    bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")

resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()

data, _ := io.ReadAll(resp.Body)
os.WriteFile("screenshot.png", data, 0644)

Error Handling

All errors return JSON with an error field and descriptive message.

StatusCodeDescription
400INVALID_JSONMalformed JSON request body
400SELECTOR_NOT_FOUNDCSS selector not found on page
400PAGE_TOO_TALLFull-page exceeds 15,000px height
413PAYLOAD_TOO_LARGERequest body exceeds 1MB
429Rate limit exceeded30 requests per minute per IP
502NETWORK_ERRORTarget URL unreachable
503CONCURRENT_LIMITToo many simultaneous captures (max 5)
504TIMEOUTPage load exceeded timeout
500CAPTURE_FAILEDGeneric screenshot failure
500CONVERSION_FAILEDImage format conversion error

Example Error Response

{
  "error": "NETWORK_ERROR",
  "message": "Could not reach the target URL. Verify the URL is accessible.",
  "url": "https://invalid-domain.example",
  "docs": "/docs#errors"
}

Rate Limits

LimitValueScope
API requests30 / minutePer IP address
Concurrent renders5Per IP address
Page load timeout30 secondsPer request
Max viewport3840 x 2160Per request

Rate limit info is returned in response headers:

X-RateLimit-Limit: 30
X-RateLimit-Remaining: 28
X-RateLimit-Reset: 1707696000

Changelog

v2.0.0 (February 2026) — Completely Free

  • Removed API key requirement — all endpoints now open
  • Removed usage limits and monthly quotas
  • Removed pricing tiers — everything is free, all features included
  • Improved browser compatibility (better Chromium flags)
  • Changed default example URL for better reliability
  • Rate limiting now per IP address (30 req/min)
  • Removed /v1/usage endpoint (no longer needed)

v1.0.1 (February 2026) - Hardened Build

  • WebP format support via Sharp
  • Structured error codes (TIMEOUT, NETWORK_ERROR, etc.)
  • SSRF protection hardened (IPv6-mapped addresses)
  • Graceful shutdown on SIGTERM/SIGINT
  • Browser warmup on startup + /ready endpoint
  • /health checks browser connectivity
  • GET /v1/usage endpoint
  • gzip compression, smart page wait
  • API keys Map bounded at 10,000 entries
  • 50+ security and reliability improvements

v1.0.0 (February 2026) - Initial Release

  • GET and POST screenshot endpoints
  • Full-page capture, dark mode, ad blocking
  • CSS injection and element selector capture
  • Device emulation and custom viewports
  • API key authentication with auto-registration
  • Rate limiting and usage tracking

Support

Need help? Here's how to reach us: