SnapAPI Documentation
One API key. Screenshots, PDFs, scraping, content extraction, video recording, and OG images. Ship in minutes, scale to millions.
Authentication
All API requests are authenticated with an API key. Pass it in the X-Api-Key header.
X-Api-Key: sk_live_xxxxxxxxxxxxxxxxxxxx
You can also pass the key as the access_key query parameter for quick tests in the browser, but the header method is required for production.
curl "https://api.snapapi.pics/v1/screenshot?access_key=sk_live_xxx&url=https://example.com" --output out.png
Never expose your API key in client-side code, public repos, or URLs you share. Always call the API from your server.
Manage keys from your dashboard. You can generate multiple keys and revoke them individually.
Quick Start
Capture your first screenshot in under 60 seconds.
-
1
Get your API key
Sign up at snapapi.pics/register. You get 200 free requests — no credit card required.
-
2
Make your first request
curl -X POST "https://api.snapapi.pics/v1/screenshot" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com"}' \ --output screenshot.pngimport fs from 'fs'; const res = await fetch('https://api.snapapi.pics/v1/screenshot', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://example.com' }), }); fs.writeFileSync('screenshot.png', Buffer.from(await res.arrayBuffer())); console.log('Saved screenshot.png');import requests r = requests.post( 'https://api.snapapi.pics/v1/screenshot', headers={'X-Api-Key': 'YOUR_API_KEY'}, json={'url': 'https://example.com'}, ) with open('screenshot.png', 'wb') as f: f.write(r.content) print('Saved screenshot.png')package main import ( "bytes" "encoding/json" "io" "net/http" "os" ) func main() { body, _ := json.Marshal(map[string]string{"url": "https://example.com"}) req, _ := http.NewRequest("POST", "https://api.snapapi.pics/v1/screenshot", bytes.NewBuffer(body)) req.Header.Set("X-Api-Key", "YOUR_API_KEY") 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) }<?php $ch = curl_init('https://api.snapapi.pics/v1/screenshot'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-Api-Key: YOUR_API_KEY', 'Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode(['url' => 'https://example.com']), ]); file_put_contents('screenshot.png', curl_exec($ch)); curl_close($ch);require 'net/http' require 'json' uri = URI('https://api.snapapi.pics/v1/screenshot') req = Net::HTTP::Post.new(uri, { 'X-Api-Key' => 'YOUR_API_KEY', 'Content-Type' => 'application/json' }) req.body = { url: 'https://example.com' }.to_json res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) } File.write('screenshot.png', res.body, mode: 'wb') -
3
You're done
The API returns the image binary directly. Save it, stream it, or upload it to S3. Explore the full parameter reference below.
Base URL & Versioning
https://api.snapapi.pics/v1
All endpoints are HTTPS only. Request and response bodies use JSON unless the endpoint returns binary (images, PDFs, videos). The current stable version is v1.
A machine-readable spec is available at /openapi.json and as interactive Swagger UI at /v1/docs.
Screenshot API
Capture pixel-perfect screenshots of any URL. Returns the image binary. Supports PNG, JPEG, WebP, and AVIF. Response time is typically 1–4 seconds.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| urlrequired | string | — | URL to capture. Must include protocol (https://) |
| format | string | png | Output format: png · jpeg · webp · avif |
| width | integer | 1280 | Viewport width in pixels (100–3840) |
| height | integer | 800 | Viewport height in pixels (100–2160) |
| fullPage | boolean | false | Capture the full scrollable page height |
| quality | integer | 80 | Compression quality 1–100 (jpeg / webp / avif only) |
| delay | integer | 0 | Wait N ms after page load before capturing (0–30000) |
| selector | string | — | CSS selector — capture only that element |
| blockAds | boolean | false | Block ad networks before capture |
| blockCookieBanners | boolean | false | Auto-dismiss cookie consent overlays |
| darkMode | boolean | false | Emulate prefers-color-scheme: dark |
| deviceScaleFactor | number | 1 | Device pixel ratio (1, 1.5, 2, 3) for retina screenshots |
| userAgent | string | — | Override the browser's User-Agent string |
| waitUntil | string | load | Navigation event: load · domcontentloaded · networkidle |
| cache | boolean | true | Return cached result if available (10-min TTL) |
| markdown | string | — | Render a markdown string to image instead of loading a URL |
Example
curl -X POST "https://api.snapapi.pics/v1/screenshot" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com",
"width": 1920,
"height": 1080,
"fullPage": true,
"format": "webp",
"quality": 90,
"blockAds": true,
"blockCookieBanners": true,
"delay": 500
}' \
--output stripe.webp
const res = await fetch('https://api.snapapi.pics/v1/screenshot', {
method: 'POST',
headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://stripe.com',
width: 1920, height: 1080, fullPage: true,
format: 'webp', quality: 90,
blockAds: true, blockCookieBanners: true, delay: 500,
}),
});
const buf = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('stripe.webp', buf);
import requests
r = requests.post(
'https://api.snapapi.pics/v1/screenshot',
headers={'X-Api-Key': 'YOUR_API_KEY'},
json={
'url': 'https://stripe.com',
'width': 1920, 'height': 1080, 'fullPage': True,
'format': 'webp', 'quality': 90,
'blockAds': True, 'blockCookieBanners': True, 'delay': 500,
},
)
with open('stripe.webp', 'wb') as f:
f.write(r.content)
payload, _ := json.Marshal(map[string]interface{}{
"url": "https://stripe.com", "width": 1920, "height": 1080,
"fullPage": true, "format": "webp", "quality": 90,
"blockAds": true, "delay": 500,
})
req, _ := http.NewRequest("POST", "https://api.snapapi.pics/v1/screenshot", bytes.NewBuffer(payload))
req.Header.Set("X-Api-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
os.WriteFile("stripe.webp", data, 0644)
Response
On success, returns the raw image binary with the corresponding Content-Type header (image/png, image/jpeg, etc.).
<binary image data>
WebP at quality 85 is typically 40% smaller than PNG with imperceptible quality loss. Use "format":"webp","quality":85 as a default.
PDF Generation
Convert any URL to a PDF document. Supports A4, Letter, Legal, and custom page sizes. Response is the PDF binary. Typical response time is 2–6 seconds.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| urlrequired | string | — | URL to convert to PDF |
| pageSize | string | a4 | Page format: a4 · letter · legal · tabloid |
| landscape | boolean | false | Use landscape orientation |
| printBackground | boolean | true | Include background colors and images |
| marginTop | string | 0 | Top margin, e.g. "20mm" or "1in" |
| marginBottom | string | 0 | Bottom margin |
| marginLeft | string | 0 | Left margin |
| marginRight | string | 0 | Right margin |
| scale | number | 1 | CSS scale factor (0.1–2.0) |
| delay | integer | 0 | Wait N ms after load before generating |
| waitUntil | string | load | Navigation event to wait for |
Example
curl -X POST "https://api.snapapi.pics/v1/pdf" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/invoice",
"pageSize": "a4",
"printBackground": true,
"marginTop": "10mm",
"marginBottom": "10mm"
}' \
--output invoice.pdf
const res = await fetch('https://api.snapapi.pics/v1/pdf', {
method: 'POST',
headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://example.com/invoice',
pageSize: 'a4', printBackground: true,
marginTop: '10mm', marginBottom: '10mm',
}),
});
require('fs').writeFileSync('invoice.pdf', Buffer.from(await res.arrayBuffer()));
r = requests.post(
'https://api.snapapi.pics/v1/pdf',
headers={'X-Api-Key': 'YOUR_API_KEY'},
json={'url': 'https://example.com/invoice', 'pageSize': 'a4',
'printBackground': True, 'marginTop': '10mm'},
)
with open('invoice.pdf', 'wb') as f:
f.write(r.content)
Extract API
Extract structured content from any webpage. Returns clean markdown, article text, metadata, links, or images. Ideal for LLM pipelines and RAG systems.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| urlrequired | string | — | URL to extract content from |
| type | string | markdown | Extraction type — see table below |
| selector | string | — | CSS selector to scope extraction to a specific element |
| maxLength | integer | — | Truncate output to N characters |
| blockAds | boolean | false | Block ads before extraction |
| waitUntil | string | networkidle | Navigation event to wait for |
| delay | integer | 0 | Extra wait in ms after navigation |
Extraction Types
| type | Returns | Best for |
|---|---|---|
| markdown | Clean markdown with headings, links, code blocks | LLM input, RAG |
| article | Title, byline, excerpt, and body via Readability | News / blog extraction |
| structured | JSON: title, author, date, description, word count | Data pipelines |
| text | Plain text, no formatting | Search indexing |
| html | Raw inner HTML | Custom parsing |
| links | Array of {text, href} | Link analysis, crawling |
| images | Array of {src, alt, width, height} | Image extraction |
| metadata | Title, OG tags, Twitter cards, favicon | SEO analysis |
Example — LLM pipeline
curl -X POST "https://api.snapapi.pics/v1/extract" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://openai.com/blog/gpt-4", "type": "markdown"}'
const { data } = await fetch('https://api.snapapi.pics/v1/extract', {
method: 'POST',
headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ url: 'https://openai.com/blog/gpt-4', type: 'markdown' }),
}).then(r => r.json());
// Feed directly to an LLM
const completion = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: 'Summarize the following article.' },
{ role: 'user', content: data },
],
});
import requests, openai
r = requests.post(
'https://api.snapapi.pics/v1/extract',
headers={'X-Api-Key': 'YOUR_API_KEY'},
json={'url': 'https://openai.com/blog/gpt-4', 'type': 'markdown'},
).json()
markdown = r['data']
# Feed directly to GPT-4o
response = openai.chat.completions.create(
model='gpt-4o',
messages=[
{'role': 'system', 'content': 'Summarize this article concisely.'},
{'role': 'user', 'content': markdown},
],
)
print(response.choices[0].message.content)
Response
{
"success": true,
"data": "# GPT-4 Technical Report\n\nGPT-4 is a large multimodal model...",
"metadata": {
"title": "GPT-4 Technical Report",
"wordCount": 2847,
"url": "https://openai.com/blog/gpt-4"
}
}
Scrape API
Scrape structured data from any URL using a headless browser with stealth mode. Handles JavaScript-rendered pages, SPAs, and bot-detection.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| urlrequired | string | — | URL to scrape |
| waitUntil | string | networkidle | load · domcontentloaded · networkidle |
| delay | integer | 0 | Extra wait in ms after navigation completes |
| selector | string | — | Wait for this CSS selector before returning |
| blockAds | boolean | false | Block ad networks |
| userAgent | string | — | Override User-Agent |
Response
{
"success": true,
"url": "https://news.ycombinator.com",
"title": "Hacker News",
"html": "<html>...full rendered HTML...</html>",
"text": "Ask HN: ... Show HN: ...",
"links": [
{ "text": "Guidelines", "href": "https://news.ycombinator.com/newsguidelines.html" }
],
"statusCode": 200
}
Video Recording NEW
Record a browser session as an MP4 video. Captures page animations, scroll behavior, and dynamic content. Response is the video binary.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| urlrequired | string | — | URL to record |
| width | integer | 1280 | Viewport width (480–1920) |
| height | integer | 720 | Viewport height (360–1080) |
| duration | integer | 5000 | Recording duration in ms (1000–30000) |
| fps | integer | 25 | Frames per second (10–60) |
| scrollDuration | integer | — | Auto-scroll the page over N ms |
| delay | integer | 500 | Wait N ms before starting recording |
| blockAds | boolean | false | Block ad networks |
Video requests are processed synchronously. Expect 5–35 seconds depending on duration. For long recordings, consider using the webhook/async flow.
AI Analyze BETA
Extract content from a URL and run it through an LLM with your prompt. Combines the Extract API with AI analysis in one call.
The Analyze endpoint is temporarily limited while we upgrade AI credits. Requests may return a graceful error. Use Extract + your own LLM call as a reliable alternative.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| urlrequired | string | — | URL to analyze |
| promptrequired | string | — | Instruction for the LLM, e.g. "Summarize this page in 3 bullet points" |
| model | string | claude-3-haiku | LLM model to use |
| maxTokens | integer | 1024 | Maximum tokens in the response |
OG Image
Generate Open Graph preview images from any URL. Returns a 1200×630 image optimized for social sharing on Twitter, LinkedIn, Slack, and Discord.
Use the Screenshot endpoint with "width":1200,"height":630 for standard OG images.
curl -X POST "https://api.snapapi.pics/v1/screenshot" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yoursite.com/blog/my-post",
"width": 1200,
"height": 630,
"format": "jpeg",
"quality": 92,
"blockAds": true,
"blockCookieBanners": true
}' \
--output og.jpg
Webhooks & Async
For long-running jobs (video recording, large PDFs), submit the request asynchronously and receive the result via webhook when processing is complete.
Async Request
Add "async": true and a "webhookUrl" to any request body.
{
"url": "https://example.com",
"fullPage": true,
"async": true,
"webhookUrl": "https://your-server.com/webhooks/snapapi"
}
The API immediately returns a job ID:
{ "jobId": "job_abc123", "status": "queued" }
Webhook Payload
When the job completes, we POST the following JSON to your webhookUrl:
{
"jobId": "job_abc123",
"status": "completed",
"imageUrl": "https://cdn.snapapi.pics/results/job_abc123.png",
"completedAt": "2026-03-17T12:34:56.789Z"
}
We retry failed webhooks with exponential backoff: 10 s, 30 s, 2 min, 10 min, 1 hour. Respond with HTTP 2xx to acknowledge.
Usage API
Query your current billing period usage programmatically.
curl "https://api.snapapi.pics/v1/usage" \
-H "X-Api-Key: YOUR_API_KEY"
{
"plan": "pro",
"requestsUsed": 4271,
"requestsLimit": 50000,
"resetAt": "2026-04-01T00:00:00.000Z",
"periodStart": "2026-03-01T00:00:00.000Z"
}
SDKs & Client Libraries
Official SDKs for all major languages. Every SDK supports all endpoints, handles auth, retries, and TypeScript types where applicable.
JavaScript / TypeScript
Full TypeScript types. Works in Node.js 18+ and modern browsers (Bun and Deno compatible).
Installation
npm install @snapapi/sdk
Quick example
import { SnapAPI } from '@snapapi/sdk';
const snap = new SnapAPI({ apiKey: process.env.SNAPAPI_KEY! });
// Screenshot
const img = await snap.screenshot({
url: 'https://stripe.com',
format: 'webp',
fullPage: true,
width: 1440,
});
await Bun.write('stripe.webp', img);
// Extract markdown for LLM
const { data } = await snap.extract({
url: 'https://news.ycombinator.com',
type: 'markdown',
});
console.log(data.substring(0, 500));
// Generate PDF
const pdf = await snap.pdf({
url: 'https://example.com/invoice',
pageSize: 'a4',
marginTop: '10mm',
});
await Bun.write('invoice.pdf', pdf);
Error handling
import { SnapAPI, SnapAPIError } from '@snapapi/sdk';
const snap = new SnapAPI({ apiKey: process.env.SNAPAPI_KEY! });
try {
const img = await snap.screenshot({ url: 'https://example.com' });
} catch (err) {
if (err instanceof SnapAPIError) {
console.error(err.code); // e.g. 'RATE_LIMITED'
console.error(err.status); // e.g. 429
console.error(err.message);
}
}
Python
Python 3.8+. Supports both sync and async (asyncio) usage. Full type hints via TypedDict.
Installation
pip install snapapi
Quick example
from snapapi import SnapAPI
snap = SnapAPI(api_key="sk_live_xxx")
# Screenshot
img_bytes = snap.screenshot(
url="https://stripe.com",
format="webp",
full_page=True,
width=1440,
)
with open("stripe.webp", "wb") as f:
f.write(img_bytes)
# Extract
result = snap.extract(
url="https://news.ycombinator.com",
type="markdown",
)
print(result["data"][:500])
# Async variant
import asyncio
from snapapi import AsyncSnapAPI
async def main():
async with AsyncSnapAPI(api_key="sk_live_xxx") as snap:
img = await snap.screenshot(url="https://example.com")
return img
asyncio.run(main())
Error handling
from snapapi import SnapAPI, SnapAPIError
snap = SnapAPI(api_key="sk_live_xxx")
try:
img = snap.screenshot(url="https://example.com")
except SnapAPIError as e:
print(e.code) # e.g. "RATE_LIMITED"
print(e.status) # e.g. 429
print(e.message)
Go
Go 1.20+. Idiomatic Go with context support, typed structs, and zero external dependencies.
Installation
go get github.com/Sleywill/snapapi-go
Quick example
package main
import (
"context"
"os"
"github.com/Sleywill/snapapi-go"
)
func main() {
client := snapapi.NewClient(os.Getenv("SNAPAPI_KEY"))
ctx := context.Background()
// Screenshot
data, err := client.Screenshot(ctx, snapapi.ScreenshotOptions{
URL: "https://stripe.com",
Format: "webp",
FullPage: true,
Width: 1440,
})
if err != nil {
log.Fatal(err)
}
os.WriteFile("stripe.webp", data, 0644)
// Extract
result, err := client.Extract(ctx, snapapi.ExtractOptions{
URL: "https://news.ycombinator.com",
Type: "markdown",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Data[:500])
}
PHP
PHP 8.0+. PSR-4 autoloading via Composer. Uses Guzzle under the hood.
Installation
composer require sleywill/snapapi-php
Quick example
<?php
require 'vendor/autoload.php';
use SnapAPI\Client;
use SnapAPI\SnapAPIException;
$snap = new Client(getenv('SNAPAPI_KEY'));
// Screenshot
$image = $snap->screenshot([
'url' => 'https://stripe.com',
'format' => 'webp',
'fullPage' => true,
'width' => 1440,
]);
file_put_contents('stripe.webp', $image);
// Extract
$result = $snap->extract([
'url' => 'https://news.ycombinator.com',
'type' => 'markdown',
]);
echo substr($result['data'], 0, 500);
// Error handling
try {
$pdf = $snap->pdf(['url' => 'https://example.com']);
} catch (SnapAPIException $e) {
echo $e->getCode() . ': ' . $e->getMessage();
}
Swift
Swift 5.7+. Native async/await. Works on iOS 15+, macOS 12+, and Linux. Distributed as a Swift Package.
Installation — Package.swift
// Package.swift
.package(url: "https://github.com/Sleywill/snapapi-swift", from: "2.0.0")
Quick example
import SnapAPI
let snap = SnapAPIClient(apiKey: ProcessInfo.processInfo.environment["SNAPAPI_KEY"]!)
// Screenshot
let imageData = try await snap.screenshot(
ScreenshotOptions(
url: "https://stripe.com",
format: .webp,
fullPage: true,
width: 1440
)
)
try imageData.write(to: URL(fileURLWithPath: "stripe.webp"))
// Extract
let result = try await snap.extract(
ExtractOptions(url: "https://news.ycombinator.com", type: .markdown)
)
print(String(result.data.prefix(500)))
// Error handling
do {
let pdf = try await snap.pdf(PDFOptions(url: "https://example.com"))
} catch let error as SnapAPIError {
print("Error \(error.statusCode): \(error.code) — \(error.message)")
}
Kotlin
Kotlin 1.7+ / JVM 11+. Coroutine-native. Distributed via JitPack.
Installation — build.gradle.kts
repositories { maven("https://jitpack.io") }
dependencies {
implementation("com.github.Sleywill.snapapi:kotlin:2.0.0")
}
Quick example
import com.snapapi.SnapAPI
import com.snapapi.ScreenshotOptions
import com.snapapi.ExtractOptions
import java.io.File
suspend fun main() {
val snap = SnapAPI(apiKey = System.getenv("SNAPAPI_KEY"))
// Screenshot
val imageBytes = snap.screenshot(
ScreenshotOptions(
url = "https://stripe.com",
format = "webp",
fullPage = true,
width = 1440,
)
)
File("stripe.webp").writeBytes(imageBytes)
// Extract
val result = snap.extract(
ExtractOptions(url = "https://news.ycombinator.com", type = "markdown")
)
println(result.data.take(500))
snap.close()
}
Ruby
Ruby 3.0+. Available as a gem. Uses Faraday for HTTP.
Installation
gem install snapapi
Quick example
require 'snapapi'
snap = SnapAPI::Client.new(api_key: ENV['SNAPAPI_KEY'])
# Screenshot
image = snap.screenshot(
url: 'https://stripe.com',
format: 'webp',
full_page: true,
width: 1440
)
File.write('stripe.webp', image, mode: 'wb')
# Extract
result = snap.extract(
url: 'https://news.ycombinator.com',
type: 'markdown'
)
puts result[:data][0..500]
# Error handling
begin
pdf = snap.pdf(url: 'https://example.com')
rescue SnapAPI::Error => e
puts "#{e.code}: #{e.message}"
end
Java
Java 11+. Uses the built-in java.net.http.HttpClient. Distributed via JitPack.
Installation — pom.xml (Maven)
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.Sleywill.snapapi</groupId>
<artifactId>java</artifactId>
<version>2.0.0</version>
</dependency>
Quick example
import com.snapapi.SnapAPI;
import com.snapapi.ScreenshotOptions;
import com.snapapi.ExtractOptions;
import java.nio.file.Files;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
SnapAPI snap = new SnapAPI(System.getenv("SNAPAPI_KEY"));
// Screenshot
byte[] image = snap.screenshot(new ScreenshotOptions()
.url("https://stripe.com")
.format("webp")
.fullPage(true)
.width(1440));
Files.write(Path.of("stripe.webp"), image);
// Extract
var result = snap.extract(new ExtractOptions()
.url("https://news.ycombinator.com")
.type("markdown"));
System.out.println(result.getData().substring(0, 500));
}
}
Error Handling
All errors return JSON with a machine-readable error.code field.
{
"success": false,
"error": {
"code": "INVALID_URL",
"message": "The provided URL is invalid. Please include the protocol (https://)."
}
}
Error Code Reference
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_URL | URL is invalid or missing protocol |
| 400 | INVALID_PARAMS | One or more parameters failed validation |
| 401 | UNAUTHORIZED | Invalid or missing API key |
| 402 | QUOTA_EXCEEDED | Monthly request quota exhausted |
| 403 | FORBIDDEN | Feature not available on your plan |
| 408 | TIMEOUT | Page load exceeded the timeout limit |
| 422 | CONTENT_VALIDATION_FAILED | Content validation conditions not met |
| 429 | RATE_LIMITED | Too many requests — slow down and retry |
| 500 | CAPTURE_FAILED | Browser failed to capture the page |
| 503 | SERVICE_UNAVAILABLE | Temporary overload — retry with backoff |
Retry strategy
async function screenshotWithRetry(options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch('https://api.snapapi.pics/v1/screenshot', {
method: 'POST',
headers: { 'X-Api-Key': process.env.SNAPAPI_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify(options),
});
if (res.ok) return Buffer.from(await res.arrayBuffer());
const { error } = await res.json();
const retryable = res.status === 429 || res.status >= 500;
if (!retryable || attempt === maxRetries) {
throw new Error(`SnapAPI error ${res.status}: ${error.code}`);
}
// Exponential backoff: 1s, 2s, 4s
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
}
}
Rate Limits
Limits are enforced per API key. Exceeding the per-minute limit returns HTTP 429. Monthly quota exhaustion returns 402.
| Plan | Requests / Min | Concurrent | Requests / Month |
|---|---|---|---|
| Free | 10 | 1 | 200 |
| Starter | 60 | 5 | 5,000 |
| Pro | 120 | 10 | 50,000 |
| Enterprise | Custom | Custom | Unlimited |
Rate limit headers are returned on every response:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1742209320
Retry-After: 3 (only on 429)
Enterprise plans include dedicated infrastructure, custom limits, and SLA guarantees. Contact us.
Caching
Screenshot and extract results are cached for 10 minutes by URL + parameter hash. Cache hits don't count against your monthly quota.
Disable cache
Pass "cache": false to always get a fresh capture.
{ "url": "https://example.com", "cache": false }
Cache busting
Changing any parameter produces a new cache key. To force a refresh without disabling cache globally, append a timestamp to a custom header field or use "cache": false once, then let the new result warm the cache.
LLM Pipelines
SnapAPI + Extract is the fastest way to feed web content into GPT-4o, Claude, or any other LLM.
import OpenAI from 'openai';
const openai = new OpenAI();
const SNAP_KEY = process.env.SNAPAPI_KEY;
async function summarizePage(url) {
// Step 1: extract markdown from any URL
const { data: markdown } = await fetch('https://api.snapapi.pics/v1/extract', {
method: 'POST',
headers: { 'X-Api-Key': SNAP_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ url, type: 'markdown' }),
}).then(r => r.json());
// Step 2: send to GPT-4o
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'system', content: 'You are a concise summarizer. Output 3 bullet points.' },
{ role: 'user', content: markdown },
],
max_tokens: 512,
});
return completion.choices[0].message.content;
}
const summary = await summarizePage('https://openai.com/blog/gpt-4');
console.log(summary);
import os
import requests
from openai import OpenAI
client = OpenAI()
SNAP_KEY = os.environ['SNAPAPI_KEY']
def summarize_page(url: str) -> str:
# Step 1: extract markdown
r = requests.post(
'https://api.snapapi.pics/v1/extract',
headers={'X-Api-Key': SNAP_KEY},
json={'url': url, 'type': 'markdown'},
)
markdown = r.json()['data']
# Step 2: send to GPT-4o-mini
completion = client.chat.completions.create(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Summarize in 3 bullet points.'},
{'role': 'user', 'content': markdown},
],
max_tokens=512,
)
return completion.choices[0].message.content
print(summarize_page('https://openai.com/blog/gpt-4'))
OpenAPI Specification
The complete OpenAPI 3.1 spec is available for use with Postman, Insomnia, Stoplight, or any code generator.