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.
https://pageshot.site/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.site/v1/screenshot?url=https://example.com" \
--output screenshot.png
# That's it! Open screenshot.png to see the result.
Authentication
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
| Header | Description |
|---|---|
X-Screenshot-Time | Capture duration (e.g., 2341ms) |
X-Page-Title | URL-encoded page title from the captured page |
X-Page-Status | HTTP status code of the target page (e.g., 200, 404) |
X-Resolved-Url | Final URL after any redirects |
Content-Type | image/png, image/jpeg, or image/webp |
GET /v1/preview
GET /v1/preview?url=https://example.com
Optimized link preview thumbnail. Returns a small, fast JPEG image with smart defaults — perfect for link cards, newsletters, social embeds, and AI vision pipelines. Ads are blocked and cookie banners hidden automatically.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | string | required | URL to capture |
width | integer | 300 | Output image width (100-800px). Height auto-scales. |
dark_mode | boolean | false | Capture in dark color scheme |
Optimized Defaults
| Setting | Value | Why |
|---|---|---|
| Output format | JPEG (quality 60) | ~5x smaller files than PNG |
| Viewport | 1280×720 | Standard desktop capture |
| Output width | 300px | Card-sized thumbnail |
| Ads blocked | Yes | Clean preview image |
| Banners hidden | Yes | No cookie consent popups |
| Timeout | 15 seconds | Fast fail for slow pages |
| Cache | 24 hours | Previews don't need real-time freshness |
Example
# Get a 300px-wide link preview thumbnail
curl "https://pageshot.site/v1/preview?url=https://example.com" \
--output preview.jpg
# Wider preview for newsletter cards
curl "https://pageshot.site/v1/preview?url=https://example.com&width=600" \
--output newsletter-card.jpg
# Embed directly in HTML
<img src="https://pageshot.site/v1/preview?url=https://example.com" alt="Preview" />
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",
"pageStatus": 200,
"image": "data:image/png;base64,iVBORw0KGgo...",
"format": "png",
"width": 1920,
"height": 1080,
"size": 245632,
"captureTime": "2341ms"
}
}
POST /v1/html
POST /v1/html
Render raw HTML/CSS to an image. Perfect for generating OG images, email previews, social cards, and dynamic content from templates. No URL needed — just send your HTML.
Request Body (JSON)
{
"html": "<div style='padding:40px;background:#0a0a0f;color:#00f0ff;font-family:sans-serif'><h1>Hello World</h1><p>Generated with PageShot</p></div>",
"width": 1200,
"height": 630,
"format": "png",
"device_scale": 2,
"response": "json"
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
html | string | Yes | Raw HTML content to render (max 2MB) |
width | integer | No | Viewport width (default: 1280, range: 320-3840) |
height | integer | No | Viewport height (default: 720, range: 200-2160) |
format | string | No | Output format: png, jpeg, webp (default: png) |
quality | integer | No | JPEG/WebP quality 1-100 (default: 80) |
device_scale | float | No | Device scale factor 0.5-3 (default: 1) |
css | string | No | Additional CSS to inject after rendering |
selector | string | No | Capture a specific element from the HTML |
full_page | boolean | No | Capture entire content height |
dark_mode | boolean | No | Force dark color scheme |
delay | integer | No | Wait before capture (ms, max 10000) |
response | string | No | Set to "json" for base64 JSON response |
Use Cases
- OG Image generation — Render dynamic Open Graph images from HTML templates
- Email previews — Generate thumbnail previews of HTML email templates
- Social cards — Create custom social media cards with dynamic data
- Certificates & badges — Generate personalized certificates or achievement badges
- Invoice thumbnails — Preview invoice or document layouts before PDF export
Example: Generate an OG Image
curl -X POST "https://pageshot.site/v1/html" \
-H "Content-Type: application/json" \
-d '{
"html": "<div style=\"width:1200px;height:630px;background:linear-gradient(135deg,#0a0a0f,#1a1a2e);display:flex;align-items:center;justify-content:center;color:#00f0ff;font-family:sans-serif\"><h1 style=\"font-size:72px\">My Blog Post Title</h1></div>",
"width": 1200,
"height": 630,
"format": "png"
}' \
--output og-image.png
POST /v1/pdf
POST /v1/pdf
Convert any webpage to a PDF document. Powered by Chromium's print engine for pixel-perfect rendering. Perfect for archiving, reports, and documentation.
Request Body (JSON)
{
"url": "https://example.com",
"pdf_format": "A4",
"landscape": false,
"print_background": true,
"pdf_scale": 1,
"dark_mode": false,
"block_ads": true,
"css": "nav { display: none !important; }"
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The webpage URL to convert to PDF |
pdf_format | string | No | Page size: A4, A3, A5, Letter, Legal, Tabloid (default: A4) |
landscape | boolean | No | Landscape orientation (default: false) |
print_background | boolean | No | Include background colors/images (default: true) |
pdf_scale | float | No | Scale of the content 0.1-2 (default: 1) |
margin | object | No | Page margins: { top, right, bottom, left } (default: 0.5in each) |
header_template | string | No | HTML template for page header |
footer_template | string | No | HTML template for page footer |
css | string | No | Custom CSS to inject before PDF generation |
block_ads | boolean | No | Block ads and trackers (default: false) |
dark_mode | boolean | No | Force dark color scheme (default: false) |
delay | integer | No | Wait before capture (ms, max 10000) |
wait_for_selector | string | No | Wait for element before generating PDF |
Response Headers
| Header | Description |
|---|---|
Content-Type | application/pdf |
X-Render-Time | Generation duration (e.g., 1523ms) |
X-Page-Title | URL-encoded page title |
X-Resolved-Url | Final URL after redirects |
Example: Save a webpage as PDF
curl -X POST "https://pageshot.site/v1/pdf" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "pdf_format": "A4", "print_background": true}' \
--output page.pdf
POST /v1/html/pdf
POST /v1/html/pdf
Render raw HTML/CSS to a PDF document. Generate invoices, reports, certificates, and documentation from HTML templates without a URL.
Request Body (JSON)
{
"html": "<h1>Invoice #1234</h1><table>...</table>",
"pdf_format": "A4",
"landscape": false,
"print_background": true
}
Parameters
Same parameters as POST /v1/pdf, but replace url with html (max 2MB).
Use Cases
- Invoice generation — Render HTML invoice templates to pixel-perfect PDFs
- Reports & documents — Generate reports from dynamic data with custom styling
- Certificates — Create personalized certificates and diplomas
- Documentation — Convert styled HTML documentation to distributable PDFs
Example: Generate an invoice PDF
curl -X POST "https://pageshot.site/v1/html/pdf" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Invoice #1234</h1><p>Total: $99.00</p>", "pdf_format": "A4"}' \
--output invoice.pdf
POST /v1/screenshot/batch
POST /v1/screenshot/batch
Capture screenshots of multiple URLs in a single request. Returns JSON with base64-encoded images for each URL. Maximum 5 URLs per batch.
Request Body (JSON)
{
"urls": [
"https://example.com",
"https://example.org",
{
"url": "https://example.net",
"width": 375,
"height": 812,
"dark_mode": true
}
],
"width": 1280,
"height": 720,
"format": "png"
}
Each entry in urls can be a plain URL string (uses global options) or an object with a url field and per-URL option overrides.
Response
{
"success": true,
"total": 3,
"succeeded": 3,
"failed": 0,
"results": [
{
"url": "https://example.com",
"success": true,
"data": {
"image": "data:image/png;base64,iVBORw0KGgo...",
"format": "png",
"width": 1280,
"height": 720,
"size": 245632,
"captureTime": "2341ms"
}
}
]
}
Limits
| Limit | Value |
|---|---|
| Max URLs per batch | 5 |
| Rate limit | 30 requests/min (shared with single screenshot) |
GET /v1/presets
GET /v1/presets
Lists all available device and platform presets. Use a preset name in the preset parameter to auto-configure viewport, scale factor, and user agent.
Available Presets
| Preset | Width | Height | Scale | Use Case |
|---|---|---|---|---|
desktop | 1920 | 1080 | 1x | Standard desktop monitor |
laptop | 1366 | 768 | 1x | Common laptop screen |
tablet | 768 | 1024 | 2x | Generic tablet |
mobile | 375 | 812 | 3x | Generic smartphone |
iphone_14 | 390 | 844 | 3x | iPhone 14 with Safari UA |
iphone_14_pro_max | 430 | 932 | 3x | iPhone 14 Pro Max with Safari UA |
pixel_7 | 412 | 915 | 2.6x | Google Pixel 7 with Chrome UA |
ipad | 820 | 1180 | 2x | iPad with Safari UA |
og_image | 1200 | 630 | 1x | Open Graph / social preview |
twitter_card | 1024 | 512 | 1x | Twitter Card preview |
linkedin_post | 1200 | 627 | 1x | LinkedIn post image |
Example: Using a Preset
curl "https://pageshot.site/v1/screenshot?url=https://example.com&preset=og_image" \
--output og-preview.png
You can override individual preset values. For example, preset=mobile&width=414 uses the mobile preset but overrides the width.
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
| Parameter | Type | Default | Description |
|---|---|---|---|
url | string | required | The webpage URL to capture |
preset | string | null | Device/platform preset (see presets) |
width | integer | 1280 | Viewport width (320-3840). Overrides preset. |
height | integer | 720 | Viewport height (200-2160) |
full_page | boolean | false | Capture entire scrollable page |
format | string | png | Output: png, jpeg, webp |
quality | integer | 80 | JPEG/WebP quality (1-100) |
dark_mode | boolean | false | Force dark color scheme |
block_ads | boolean | false | Block ads and trackers (also dismisses banners) |
hide_banners | boolean | false | Dismiss cookie banners, consent popups, GDPR overlays, and chat widgets before capture |
delay | integer | 0 | Wait before capture (ms, max 10000) |
device_scale | float | 1 | Device scale factor (0.5-3) |
selector | string | null | CSS selector for element capture |
wait_for_selector | string | null | Wait for this CSS selector to be visible before capture |
css | string | null | Custom CSS to inject |
user_agent | string | null | Custom User-Agent string |
timeout | integer | 30000 | Page load timeout (ms, 5000-60000) |
resize_width | integer | null | Resize output image to this width in px (16-3840). Maintains aspect ratio. |
resize_height | integer | null | Resize output image to this height in px (16-2160). Maintains aspect ratio. |
headers | object | null | Custom HTTP headers to send (e.g., {"Authorization": "Bearer token"}). Max 20 headers. POST only. |
cookies | array | null | Cookies to set before capture. Array of {"name", "value"} objects (max 50). Scoped to target domain. POST only. |
evaluate | string | null | JavaScript code to execute on the page before capture (max 10KB). Runs in the browser context. Use to dismiss modals, click buttons, or set UI state. |
clip_x | integer | null | Region capture: X coordinate (0-15000). Requires clip_y, clip_width, clip_height. |
clip_y | integer | null | Region capture: Y coordinate (0-15000) |
clip_width | integer | null | Region capture: width in pixels (1-15000) |
clip_height | integer | null | Region capture: height in pixels (1-15000) |
timezone | string | null | IANA timezone ID for the browser context (e.g., America/New_York, Europe/Berlin, Asia/Tokyo). Affects Date, Intl, and locale-aware rendering. |
locale | string | null | BCP 47 locale tag for the browser context (e.g., en-US, de-DE, ja-JP). Affects number/date formatting and navigator.language. |
disable_javascript | boolean | false | Disable JavaScript execution on the page. Captures static HTML only. Useful for security research, avoiding JS-driven redirects, or capturing pages without fingerprinting scripts. |
latitude | float | null | Geolocation emulation: latitude (-90 to 90). Must be used together with longitude. |
longitude | float | null | Geolocation emulation: longitude (-180 to 180). Must be used together with latitude. Triggers geo-targeted content rendering. |
wait_until | string | domcontentloaded | Page load strategy: commit (fastest — response received), domcontentloaded (DOM parsed), load (all resources loaded), networkidle (no network activity for 500ms — best for SPAs and lazy-loaded content). |
ignore_https_errors | boolean | false | Ignore HTTPS/TLS certificate errors. Useful for capturing dev/staging environments with self-signed certificates. |
response | string | binary | Set to json for base64 response |
Code Examples
Node.js / JavaScript
// Using fetch (Node 18+) — no API key needed
const response = await fetch('https://pageshot.site/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')}`);
Pre-Capture JavaScript (evaluate)
// Dismiss a modal and scroll before capturing
const response = await fetch('https://pageshot.site/v1/screenshot', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://example.com',
evaluate: 'document.querySelector(".modal-close")?.click(); window.scrollTo(0, 500);',
width: 1280,
height: 720
})
});
Authenticated Screenshot (with cookies & headers)
// Capture a page behind authentication
const response = await fetch('https://pageshot.site/v1/screenshot', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://app.example.com/dashboard',
headers: { 'Authorization': 'Bearer eyJhbGci...' },
cookies: [
{ name: 'session_id', value: 'abc123' },
{ name: 'csrf_token', value: 'xyz789' }
],
width: 1920,
height: 1080
})
});
Python
import requests
# No API key needed — just send the request
response = requests.post(
'https://pageshot.site/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.site/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.site/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.site/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.
| Status | Code | Description |
|---|---|---|
| 400 | INVALID_JSON | Malformed JSON request body |
| 400 | SELECTOR_NOT_FOUND | CSS selector not found on page |
| 408 | WAIT_FOR_SELECTOR_TIMEOUT | wait_for_selector element did not appear in time |
| 400 | PAGE_TOO_TALL | Full-page exceeds 15,000px height |
| 400 | EVALUATE_FAILED | JavaScript evaluation failed (syntax error or runtime exception) |
| 413 | PAYLOAD_TOO_LARGE | Request body exceeds 1MB |
| 429 | Rate limit exceeded | 30 requests per minute per IP |
| 502 | NETWORK_ERROR | Target URL unreachable |
| 503 | CONCURRENT_LIMIT | Too many simultaneous captures (max 5) |
| 504 | TIMEOUT | Page load exceeded timeout |
| 500 | CAPTURE_FAILED | Generic screenshot failure |
| 500 | CONVERSION_FAILED | Image 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
| Limit | Value | Scope |
|---|---|---|
| API requests | 30 / minute | Per IP address |
| Concurrent renders | 5 | Per IP address |
| Page load timeout | 30 seconds | Per request |
| Max viewport | 3840 x 2160 | Per request |
Rate limit info is returned in response headers:
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 28
X-RateLimit-Reset: 1707696000
MCP Integration
PageShot ships with a built-in Model Context Protocol (MCP) server. Connect PageShot directly to Claude, VS Code, Cursor, or any MCP-compatible AI client to take screenshots from your assistant.
Installation
Add the following to your MCP client configuration:
{
"mcpServers": {
"pageshot": {
"command": "npx",
"args": ["-y", "pageshot-api"]
}
}
}
Available Tools
| Tool | Description | Parameters |
|---|---|---|
take_screenshot |
Capture a screenshot of any webpage | url (required), preset, width, height, format, quality, full_page, dark_mode, delay, selector, wait_for_selector, hide_banners, resize_width, resize_height, headers, cookies, evaluate, clip_x/clip_y/clip_width/clip_height |
Environment Variables
| Variable | Default | Description |
|---|---|---|
PAGESHOT_BASE_URL |
https://pageshot.site |
Override the base URL for API requests (e.g., for self-hosted instances) |
Terms of Service
By using the PageShot API, you agree to the following terms:
- The API is provided "as is" without warranty of any kind, express or implied.
- You may use the API for lawful purposes only. Capturing screenshots of illegal content, phishing pages, or content you do not have rights to view is prohibited.
- We reserve the right to rate-limit or block access to any IP address that abuses the service.
- You may not use the API to systematically scrape or archive websites without the site owner's consent.
- We are not liable for any damages arising from the use of this service.
- These terms may be updated at any time. Continued use constitutes acceptance of updated terms.
Privacy Policy
PageShot is designed with privacy in mind:
- No accounts or personal data: We do not require signup, email, or any personal information to use the API.
- No screenshot storage: Screenshots are generated on-the-fly and streamed directly to you. We do not store, cache, or log captured images.
- Minimal logging: We log request metadata (IP address, timestamp, requested URL) for rate limiting and abuse prevention only. Logs are retained for a maximum of 30 days.
- No cookies or tracking: The API does not set cookies or use any tracking technologies.
- No third-party sharing: We do not sell, share, or transfer any data to third parties.
- Contact: For privacy-related inquiries, email damian.pozimski@gmail.com.
Support
Need help? Here's how to reach us:
- Documentation: You're reading it!
- GitHub: github.com/softvoyagers
- Email: damian.pozimski@gmail.com
- Status Page: /v1/status