API Documentation
Everything you need to integrate Pixcap's screenshot API into your application.
Introduction
Pixcap provides a simple REST API to capture high-quality screenshots of any public website. Make an HTTP request with a target URL, and receive a pixel-perfect screenshot in return.
Base URL
https://pixcap.dev/api/v1
Authentication
All API requests require authentication using an API key. You can pass your key in two ways:
Header (Recommended)
X-API-Key: pix_your_api_key_here
Query Parameter
?api_key=pix_your_api_key_here
Quick Start
Capture your first screenshot in seconds:
cURL
curl "https://pixcap.dev/api/v1/screenshot?url=https://github.com" \
-H "X-API-Key: pix_your_api_key" \
-o screenshot.png
Node.js
const response = await fetch(
'https://pixcap.dev/api/v1/screenshot?url=https://github.com',
{ headers: { 'X-API-Key': 'pix_your_api_key' } }
);
const buffer = await response.arrayBuffer();
fs.writeFileSync('screenshot.png', Buffer.from(buffer));
Python
import requests
response = requests.get(
'https://pixcap.dev/api/v1/screenshot',
params={'url': 'https://github.com'},
headers={'X-API-Key': 'pix_your_api_key'}
)
with open('screenshot.png', 'wb') as f:
f.write(response.content)
GET /screenshot
Capture a screenshot and receive the image directly in the response body.
Example
GET /api/v1/screenshot?url=https://stripe.com&width=1440&format=png
Response Headers
| Header | Description |
|---|---|
| Content-Type | image/png or image/jpeg |
| X-Screenshot-Width | Actual width of screenshot |
| X-Screenshot-Height | Actual height of screenshot |
| X-Response-Time | Time to capture (e.g., "2340ms") |
| X-Credits-Remaining | Your remaining credit balance |
POST /screenshot
Capture a screenshot and receive a JSON response with base64-encoded image.
Request Body
{
"url": "https://github.com",
"width": 1920,
"height": 1080,
"format": "png",
"fullPage": false
}
Response
{
"success": true,
"data": {
"image": "iVBORw0KGgoAAAANSUhEUgAA...",
"metadata": {
"url": "https://github.com",
"width": 1920,
"height": 1080,
"format": "png",
"responseTimeMs": 2340,
"timestamp": "2024-01-15T10:30:00.000Z"
},
"credits_remaining": 95
}
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Required | The URL to capture. Must be http or https. |
| width | integer | Optional | Viewport width (320-3840). Default: 1280 |
| height | integer | Optional | Viewport height (200-2160). Default: 800 |
| format | string | Optional | "png" or "jpeg". Default: "png" |
| quality | integer | Optional | JPEG quality (1-100). Default: 80 |
| full_page | boolean | Optional | Capture full scrollable page. Default: false |
| delay | integer | Optional | Wait time in ms after load (0-10000) |
| selector | string | Optional | CSS selector to capture specific element |
| dark_mode | boolean | Optional | Emulate dark mode. Default: false |
| scale | number | Optional | Device scale factor (1-3). Default: 1 |
| cookies | array | Optional | Array of cookie objects to set before loading. Each: {name, value, domain?, path?} |
| block_selectors | array | Optional | CSS selectors to hide (e.g., [".modal", ".cookie-banner"]) |
| wait_for_selector | string | Optional | Wait for this CSS selector to appear before capturing |
| dismiss_cookie_consent | boolean | Optional | Auto-dismiss common cookie consent banners. Default: false |
Advanced Options
Setting Cookies
Pass cookies to capture authenticated pages or maintain session state:
// POST request with cookies
{
"url": "https://example.com/dashboard",
"cookies": [
{
"name": "session_id",
"value": "abc123xyz",
"domain": "example.com"
},
{
"name": "auth_token",
"value": "Bearer_token_here",
"domain": ".example.com",
"path": "/"
}
]
}
Blocking Elements
Hide modals, popups, banners, or any other elements before capturing:
// Hide cookie banners and modals
{
"url": "https://example.com",
"blockSelectors": [
".cookie-banner",
".newsletter-popup",
"#modal-overlay",
"[data-testid='promo-banner']"
]
}
Waiting for Content
Wait for dynamic content to load before capturing (useful for SPAs):
// Wait for main content to render
{
"url": "https://spa-example.com",
"waitForSelector": ".main-content-loaded",
"delay": 500
}
Auto-Dismiss Cookie Consent
Automatically click common "Accept" buttons on cookie consent banners:
// Dismiss cookie banners automatically
{
"url": "https://news-site.com",
"dismissCookieConsent": true
}
This works with most major cookie consent providers including OneTrust, Cookiebot, and common custom implementations.
Bulk Screenshots
Capture screenshots of an entire website by providing a sitemap XML URL. Perfect for creating visual archives, monitoring site-wide changes, or generating preview images at scale.
Key Features
- Process up to 100 pages per job
- Concurrent processing for speed
- ZIP download with organized directory structure
- Credits pre-authorized and refunded for failures
- Manifest file with job metadata included
- 24-hour download window
Create Bulk Job
Submit a sitemap URL to start capturing screenshots of all pages.
Request Body
You can provide either a url (auto-detects sitemap) or sitemap_url (explicit sitemap):
// Option 1: Auto-detect sitemap (recommended)
{
"url": "example.com",
"options": { "maxPages": 50 }
}
// Option 2: Explicit sitemap URL
{
"sitemap_url": "https://example.com/sitemap.xml",
"options": { "maxPages": 50 }
}
url, we check robots.txt and common paths like /sitemap.xml to find the sitemap automatically. Works with or without https://.
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Option 1 | Website URL - sitemap will be auto-detected |
| sitemap_url | string | Option 2 | Direct URL to sitemap XML file |
| options.maxPages | integer | Optional | Maximum pages to capture (1-100). Default: 100 |
| options.width | integer | Optional | Viewport width. Default: 1280 |
| options.height | integer | Optional | Viewport height. Default: 800 |
| options.format | string | Optional | "png" or "jpeg". Default: "png" |
| options.fullPage | boolean | Optional | Capture full scrollable page. Default: false |
Response
{
"success": true,
"data": {
"job_id": "f147c641-f644-429c-8395-2ed9cdf30154",
"status": "pending",
"sitemap_url": "https://example.com/sitemap.xml",
"total_urls": 42,
"credits_reserved": 42,
"credits_remaining": 58,
"status_url": "/api/v1/bulk-screenshot/f147c641.../status"
}
}
Check Job Status
Poll this endpoint to track the progress of your bulk screenshot job.
Response
{
"success": true,
"data": {
"jobId": "f147c641-f644-429c-8395-2ed9cdf30154",
"status": "completed",
"sitemapUrl": "https://example.com/sitemap.xml",
"progress": {
"totalUrls": 42,
"processed": 42,
"successful": 40,
"failed": 2,
"percentage": 100
},
"credits": {
"reserved": 42,
"used": 40,
"refunded": 2
},
"download": {
"expiresAt": "2024-01-16T10:30:00.000Z",
"fileSize": 15728640
}
}
}
Job Status Values
| Status | Description |
|---|---|
| pending | Job created, waiting to start |
| processing | Screenshots being captured |
| packaging | Creating ZIP file |
| completed | Ready for download |
| failed | Job failed (credits refunded) |
Download ZIP
Download the completed screenshot archive. Available for 24 hours after completion.
ZIP Structure
screenshots-example-com-2024-01-15/
_manifest.json # Job metadata and URL list
index.png # https://example.com/
about/
index.png # https://example.com/about/
blog/
index.png # https://example.com/blog/
my-post.png # https://example.com/blog/my-post
Example Workflow
# 1. Create a bulk job (sitemap auto-detected)
curl -X POST "https://pixcap.dev/api/v1/bulk-screenshot" \
-H "X-API-Key: pix_your_api_key" \
-H "Content-Type: application/json" \
-d '{"url": "example.com", "options": {"maxPages": 20}}'
# 2. Check status (poll until completed)
curl "https://pixcap.dev/api/v1/bulk-screenshot/{job_id}/status" \
-H "X-API-Key: pix_your_api_key"
# 3. Download ZIP when ready
curl "https://pixcap.dev/api/v1/bulk-screenshot/{job_id}/download" \
-H "X-API-Key: pix_your_api_key" \
-o screenshots.zip
VPN Connectors
Capture screenshots of internal websites without exposing them to the internet. Deploy a lightweight connector inside your network to screenshot private dashboards, staging environments, and internal applications.
Architecture
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Your App │ │ Pixcap Cloud │ │ Connector │
│ │ │ │ │ (Your Network) │
└────────┬────────┘ └────────┬─────────┘ └────────┬────────┘
│ │ │
│ 1. API Request │ │
│ with connector_id │ │
│───────────────────────>│ │
│ │ │
│ │ 2. Route via WebSocket │
│ │────────────────────────>│
│ │ │
│ │ 3. Capture screenshot
│ │ of internal URL
│ │ │
│ │ 4. Return image │
│ │<────────────────────────│
│ │ │
│ 5. Screenshot response │ │
│<───────────────────────│ │
Key Benefits
- Security – Internal apps stay private, only outbound connections needed
- No firewall changes – Works behind NAT and corporate firewalls
- Same pricing – 1 credit per screenshot, same as cloud
- Easy deployment – Single Docker command or npm install
Quick Start
Get up and running in under 5 minutes:
1. Create a Connector
Log in to your dashboard, scroll to the VPN Connectors section, and click "Create New Connector". Copy the token—it's only shown once.
2. Deploy the Connector
docker run -d \
-e PIXCAP_CONNECTOR_TOKEN=pxc_your_token \
--restart unless-stopped \
--name pixcap-connector \
dashah2/pixcap-connector
3. Take a Screenshot
Once your connector shows "Online" in the dashboard, make a request with your connector_id:
curl "https://pixcap.dev/api/v1/screenshot?url=http://internal.example.com&connector_id=conn_YOUR_ID" \
-H "X-API-Key: pix_YOUR_API_KEY" \
-o screenshot.png
Installation
Docker (Recommended)
docker run -d \
-e PIXCAP_CONNECTOR_TOKEN=pxc_your_token \
--restart unless-stopped \
--name pixcap-connector \
dashah2/pixcap-connector
Docker Compose
version: '3.8'
services:
pixcap-connector:
image: dashah2/pixcap-connector:latest
environment:
- PIXCAP_CONNECTOR_TOKEN=${PIXCAP_CONNECTOR_TOKEN}
restart: unless-stopped
npm
npm install -g pixcap-connector
PIXCAP_CONNECTOR_TOKEN=pxc_your_token pixcap-connector
From Source
git clone https://github.com/dan-shah/pixcap.git
cd dashah2/pixcap-connector
npm install
PIXCAP_CONNECTOR_TOKEN=pxc_your_token npm start
Configuration
Configure the connector using environment variables:
| Variable | Default | Description |
|---|---|---|
| PIXCAP_CONNECTOR_TOKEN | Required | Your connector token from the dashboard |
| PIXCAP_API_URL | wss://pixcap.dev/ws/connector | WebSocket endpoint URL |
| SCREENSHOT_TIMEOUT | 30000 | Screenshot timeout in milliseconds |
| PUPPETEER_EXECUTABLE_PATH | (auto-detect) | Path to Chrome/Chromium executable |
| DEFAULT_VIEWPORT_WIDTH | 1280 | Default viewport width |
| DEFAULT_VIEWPORT_HEIGHT | 800 | Default viewport height |
API Reference
Use the connector_id parameter to route screenshot requests through your connector.
GET Request
curl "https://pixcap.dev/api/v1/screenshot?url=http://internal-app.local&connector_id=conn_abc123" \
-H "X-API-Key: pix_your_api_key" \
-o screenshot.png
POST Request
{
"url": "http://internal-app.local:3000/dashboard",
"connectorId": "conn_abc123",
"width": 1920,
"height": 1080
}
Connector Parameter
| Parameter | Type | Description |
|---|---|---|
| connector_id / connectorId | string | Your connector ID (from the dashboard). When specified, the request is routed through your connector instead of Pixcap cloud. |
Response Headers
When a request is routed through a connector, an additional header is included:
| Header | Description |
|---|---|
| X-Connector-Used | The connector ID that processed the request |
Connector Error Codes
| Code | Status | Description |
|---|---|---|
| CONNECTOR_NOT_FOUND | 404 | Connector ID doesn't exist or doesn't belong to your account |
| CONNECTOR_OFFLINE | 503 | Connector is not currently connected |
| CONNECTOR_TIMEOUT | 504 | Connector didn't respond in time |
Manage Connectors
Create and manage connectors via API or dashboard.
List Connectors
Create Connector
{
"name": "Office Network"
}
Delete Connector
Regenerate Token
Troubleshooting
Connector shows "Offline"
- Check the connector is running:
docker logs pixcap-connector - Verify your token is correct and hasn't been regenerated
- Ensure outbound WebSocket connections are allowed (port 443)
- Check for firewall rules blocking wss://pixcap.dev
Screenshots timeout
- Increase
SCREENSHOT_TIMEOUTenvironment variable - Check if the target URL is accessible from the connector host
- Verify Chrome/Chromium is installed correctly
- Test connectivity:
docker exec pixcap-connector curl http://your-internal-url
Browser launch fails
Set the Chrome path explicitly:
# Linux
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
# macOS
PUPPETEER_EXECUTABLE_PATH="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
# Docker (usually auto-detected)
# The Docker image includes Chromium
Connection keeps dropping
- The connector includes auto-reconnect with exponential backoff
- Check for proxy or firewall issues with WebSocket connections
- Review logs for disconnection reasons:
docker logs -f pixcap-connector
Register
Create a new account and receive your API key.
Request
{
"email": "you@company.com"
}
Response
{
"success": true,
"data": {
"message": "Account created successfully",
"email": "you@company.com",
"api_key": "pix_a1b2c3d4e5f6...",
"credits": 100
}
}
API Keys
You can create up to 5 API keys per account.
Create New Key
Deactivate Key
Error Codes
| Code | Status | Description |
|---|---|---|
| API_KEY_REQUIRED | 401 | No API key provided |
| INVALID_API_KEY | 401 | API key is invalid or inactive |
| INSUFFICIENT_CREDITS | 402 | No credits remaining |
| INVALID_URL | 400 | URL is not valid |
| URL_BLOCKED | 400 | URL is blocked (localhost, internal IPs) |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests |
| CAPTURE_ERROR | 500 | Failed to capture screenshot |
Rate Limits
To ensure fair usage and platform stability:
| Endpoint | Limit | Window |
|---|---|---|
| /screenshot | 60 requests | 1 minute |
| /bulk-screenshot | 10 jobs | 1 hour |
| General API | 100 requests | 1 minute |
| Registration | 10 requests | 15 minutes |
Rate limit headers are included in all responses:
X-RateLimit-Limit– Maximum requests allowedX-RateLimit-Remaining– Requests remainingX-RateLimit-Reset– When the limit resets