API Documentation

pxshot captures any webpage and returns a raw image or PDF file via a simple HTTP GET request.

Quick Start

1. Sign up at pxshot.dev/register.

2. Create an API key in your dashboard.

3. Make your first request:

curl "https://pxshot.dev/api/capture?url=https://example.com&api_key=YOUR_KEY" \
  --output screenshot.png

Authentication

pxshot authenticates requests using API keys. You can pass your key in either of two ways:

  • Query parameter: api_key=YOUR_KEY
  • Request header: X-API-Key: YOUR_KEY

API keys have the format px_.... Keep your key secret: do not commit it to source code or expose it in client-side JavaScript unless you have set an origin lock.

Origin locking: In the dashboard you can restrict an API key to only work from specific HTTP origins (e.g. https://yourapp.com). Requests from any other origin are rejected with 403. This makes it safe to include the key in client-side code.

GET /api/capture

The capture endpoint. Returns raw image bytes (or PDF bytes) with the appropriate Content-Type header. All parameters are passed as query string parameters.

GET https://pxshot.dev/api/capture?url=URL&api_key=KEY[&format=png][&width=1280][&height=720]

On success the response is HTTP 200 with the raw image or PDF binary. Errors return JSON with { "ok": false, "error": "message" }.

Parameters

ParameterTypeRequiredDescription
urlstringrequiredThe URL to capture. https:// is assumed when the protocol is missing.
api_keystringrequiredYour API key. Alternatively pass as an X-API-Key request header.
formatstringoptionalOutput format: png (default), jpeg, webp, or pdf. Pro/Business plan required for non-PNG.
widthintegeroptionalViewport width in pixels. Default: 1280. Min: 320. Max by plan: Free 1280, Pro 1920, Business 3840.
heightintegeroptionalViewport height in pixels. Default: 720. Min: 200. Max by plan: Free 720, Pro 1080, Business 2160.
full_pagebooleanoptionalCapture the full scrollable page instead of only the viewport. Default: false. Pro/Business required.
delayintegeroptionalMilliseconds to wait after page load before capturing. Default: 0. Max: 10000. Pro/Business required.
qualityintegeroptionalImage quality 1-100 for JPEG/WebP output. Default: 80. Ignored for PNG and PDF.
transparentbooleanoptionalOmit the page background for a transparent PNG. PNG format only. Pro/Business required.
headersstringoptionalJSON object of extra HTTP headers to send to the target page, e.g. {"X-Auth-Token":"secret"}. URL-encode it. Pro/Business required.
block_jsbooleanoptionalDisable JavaScript on the target page before rendering. Business plan required.
selectorstringoptionalCSS selector to clip the screenshot to one element, e.g. #chart. If it does not match, the full viewport is returned. Business plan required.

Response Format

Successful responses (HTTP 200) return raw binary image or PDF data. The following headers are always included:

  • Content-Type: image/png, or image/jpeg, image/webp, application/pdf
  • Content-Length: byte size of the response body
  • X-Screenshot-Id: unique ID for this screenshot, logged in your dashboard
  • X-Duration-Ms: time in milliseconds taken to capture the page
  • X-RateLimit-Remaining: requests remaining in the current per-minute window
  • X-Monthly-Used: screenshots used so far this billing period
  • X-Monthly-Limit: total monthly limit on your current plan
  • Cache-Control: public, max-age=300: responses are cacheable for 5 minutes

Error responses return JSON: { "ok": false, "error": "message" }

Error Codes

StatusNameDescription
400Bad RequestMissing required parameter (url or api_key), or invalid URL.
401UnauthorizedInvalid, inactive, or missing API key.
403ForbiddenOrigin restriction violation, or plan does not support the requested feature (e.g. non-PNG format on Free plan).
429Too Many RequestsMonthly screenshot limit exceeded or per-minute rate limit hit. Check X-Monthly-Used / X-RateLimit-Remaining headers.
502Bad GatewayThe target site could not be loaded: domain does not resolve, connection refused or reset, invalid SSL certificate, or a redirect loop.
504Gateway TimeoutThe target page took too long to load. Retry, or use the delay parameter for slow pages.
500Internal Server ErrorScreenshot capture failed (e.g. page unreachable, browser timeout).

Rate Limits

Two separate limits apply: a monthly quota, enforced per account, and a per-minute burst limit, enforced per API key. Exceeding either returns HTTP 429.

PlanMonthlyPer MinuteAPI KeysFormats
Free5051PNG
Pro2,000303PNG, JPEG, WebP, PDF
Business10,00010010All

Official SDK

pxshot-api is the official JavaScript/TypeScript client. Zero dependencies, typed options for every parameter, works in Node 18+, browsers, and edge runtimes. Source on GitHub.

npm install pxshot-api
import Pxshot from 'pxshot-api';
import { writeFile } from 'node:fs/promises';

const pxshot = new Pxshot('px_your_key');

const shot = await pxshot.capture('https://example.com', {
  format: 'png',
  fullPage: true,
});

await writeFile('example.png', Buffer.from(shot.data));
console.log(`${shot.durationMs}ms, ${shot.monthlyUsed} of ${shot.monthlyLimit} used`);

Errors throw a typed PxshotError with the HTTP status and the API's message. Prefer streaming? captureResponse() returns the raw Response.

Code Examples

cURL

curl "https://pxshot.dev/api/capture?url=https://example.com&api_key=YOUR_KEY&format=png&width=1280&height=720" \
  --output screenshot.png

JavaScript (fetch)

const params = new URLSearchParams({
  url: 'https://example.com',
  api_key: 'YOUR_KEY',
  format: 'webp',
  width: '1280',
  height: '720',
});

const response = await fetch(`https://pxshot.dev/api/capture?${params}`);

if (!response.ok) {
  const err = await response.json();
  throw new Error(err.error);
}

const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);
// Use imageUrl to display or download the image

JavaScript, using the X-API-Key header

const params = new URLSearchParams({
  url: 'https://example.com',
  format: 'png',
  width: '1920',
  height: '1080',
  full_page: 'true',
});

const response = await fetch(`https://pxshot.dev/api/capture?${params}`, {
  headers: { 'X-API-Key': 'YOUR_KEY' },
});

const blob = await response.blob();

Node.js

import fs from 'fs';

const params = new URLSearchParams({
  url: 'https://example.com',
  api_key: 'YOUR_KEY',
  format: 'png',
  width: '1920',
  height: '1080',
  full_page: 'true',
});

const res = await fetch(`https://pxshot.dev/api/capture?${params}`);
if (!res.ok) throw new Error(`pxshot error: ${res.status}`);

const buffer = await res.arrayBuffer();
fs.writeFileSync('screenshot.png', Buffer.from(buffer));
console.log('Duration:', res.headers.get('X-Duration-Ms'), 'ms');

Python

import requests

params = {
    'url': 'https://example.com',
    'api_key': 'YOUR_KEY',
    'format': 'jpeg',
    'width': 1280,
    'height': 720,
    'quality': 90,
}

response = requests.get('https://pxshot.dev/api/capture', params=params)
response.raise_for_status()

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

print('Duration:', response.headers.get('X-Duration-Ms'), 'ms')