How to Capture Website Screenshots with an API (Node.js, Python, cURL)
If you've ever tried to capture website screenshots programmatically, you know the pain: spinning up headless Chrome, managing Puppeteer dependencies, handling timeouts, dealing with cookie banners, and watching your server's memory spike to 2GB.
There's a better way. Screenshot APIs let you offload all that complexity to a managed service. You send a URL, you get back an image. Simple.
In this guide, I'll show you how to capture screenshots, generate PDFs, and extract structured data from websites using SnapAPI — with working code examples in Node.js, Python, and cURL.
Why Use a Screenshot API?
Before we dive into code, let's talk about why you'd want this:
- No infrastructure to manage — No headless Chrome, no Puppeteer updates, no memory issues
- Cookie banner blocking — Automatically removes GDPR popups
- Consistent rendering — Same result every time, on any device preset
- Scales to millions — Your server doesn't need 8GB RAM per browser instance
- Multiple formats — PNG, JPEG, WebP, AVIF from a single endpoint
If you're building link previews, generating social media cards, archiving web pages, or monitoring competitor sites — a screenshot API saves you weeks of development time.
Getting Started
First, grab a free API key from snapapi.pics. The free tier includes 100 screenshots/month with no credit card required.
Your API key will look like: sk_live_xxxxxxxxxxxx
All requests use the x-api-key header for authentication.
1. Capturing Screenshots
cURL
The simplest way to test:
curl -X POST "https://api.snapapi.pics/v1/screenshot" \
-H "x-api-key: sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://github.com",
"format": "png",
"width": 1280,
"height": 800
}' \
--output screenshot.png
This captures a 1280x800 screenshot of GitHub's homepage and saves it as screenshot.png.
Node.js
const fs = require('fs');
async function captureScreenshot(url, options = {}) {
const response = 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({
url,
format: options.format || 'png',
width: options.width || 1280,
height: options.height || 800,
fullPage: options.fullPage || false,
blockCookieBanners: true,
blockAds: true,
}),
});
if (!response.ok) {
throw new Error(`Screenshot failed: ${response.status}`);
}
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync('screenshot.png', buffer);
console.log('Screenshot saved!');
return buffer;
}
// Usage
captureScreenshot('https://github.com', {
format: 'webp',
fullPage: true,
});
Python
import requests
import os
def capture_screenshot(url, **kwargs):
response = requests.post(
'https://api.snapapi.pics/v1/screenshot',
headers={
'x-api-key': os.environ['SNAPAPI_KEY'],
'Content-Type': 'application/json',
},
json={
'url': url,
'format': kwargs.get('format', 'png'),
'width': kwargs.get('width', 1280),
'height': kwargs.get('height', 800),
'fullPage': kwargs.get('full_page', False),
'blockCookieBanners': True,
'blockAds': True,
}
)
response.raise_for_status()
with open('screenshot.png', 'wb') as f:
f.write(response.content)
print('Screenshot saved!')
return response.content
# Usage
capture_screenshot('https://github.com', format='webp', full_page=True)
2. Advanced Screenshot Options
SnapAPI supports a bunch of useful options:
{
"url": "https://example.com",
"format": "avif",
"width": 1440,
"height": 900,
"fullPage": true,
"devicePreset": "iPhone 15 Pro",
"darkMode": true,
"blockCookieBanners": true,
"blockAds": true,
"delay": 2000,
"selector": "#main-content",
"customCSS": "body { background: white; }",
"customJS": "document.querySelector('.popup')?.remove();"
}
Key features:
- 26+ device presets — iPhone, iPad, Pixel, Galaxy, and more
- AVIF format — 50-80% smaller files than PNG
- Selector targeting — Screenshot just a specific element
- Custom CSS/JS injection — Modify the page before capture
- Dark mode — Render in dark color scheme
3. Generating PDFs
Same API, different endpoint:
async function generatePDF(url) {
const response = 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({
url,
format: 'pdf',
pdfFormat: 'A4',
pdfPrintBackground: true,
pdfMargin: { top: '1cm', bottom: '1cm', left: '1cm', right: '1cm' },
}),
});
const buffer = Buffer.from(await response.arrayBuffer());
require('fs').writeFileSync('page.pdf', buffer);
console.log('PDF saved!');
}
generatePDF('https://example.com/invoice');
PDF options include format (A4, Letter, Legal), margins, headers/footers, and background printing.
4. Extracting Structured Data
This is where it gets really interesting. The Extract API pulls structured data from any webpage — perfect for feeding into LLMs or building data pipelines:
async function extractData(url, type = 'structured') {
const response = await fetch('https://api.snapapi.pics/v1/extract', {
method: 'POST',
headers: {
'x-api-key': process.env.SNAPAPI_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url,
type, // 'markdown', 'text', 'structured', 'metadata', 'links', 'images'
cleanOutput: true,
blockAds: true,
}),
});
const data = await response.json();
console.log(data);
return data;
}
// Get clean markdown (great for LLMs)
extractData('https://dev.to', 'markdown');
// Get metadata (OG tags, title, description)
extractData('https://dev.to', 'metadata');
// Get all links on a page
extractData('https://dev.to', 'links');
The structured type returns title, author, word count, and cleaned content — ideal for building RAG pipelines or content analysis tools.
Python Example
def extract_metadata(url):
response = requests.post(
'https://api.snapapi.pics/v1/extract',
headers={
'x-api-key': os.environ['SNAPAPI_KEY'],
'Content-Type': 'application/json',
},
json={
'url': url,
'type': 'metadata',
}
)
data = response.json()
meta = data['data']
print(f"Title: {meta['title']}")
print(f"Description: {meta['description']}")
print(f"OG Image: {meta['ogImage']}")
return meta
extract_metadata('https://github.com')
5. Real-World Use Cases
Link Previews (Like Slack)
Combine the Extract API for metadata + Screenshot API for thumbnails:
async function generateLinkPreview(url) {
// Get metadata
const metaResponse = await fetch('https://api.snapapi.pics/v1/extract', {
method: 'POST',
headers: {
'x-api-key': process.env.SNAPAPI_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ url, type: 'metadata' }),
});
const { data: meta } = await metaResponse.json();
// Get screenshot thumbnail
const screenshotResponse = 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({
url,
format: 'webp',
width: 600,
height: 400,
blockCookieBanners: true,
}),
});
return {
title: meta.ogTitle || meta.title,
description: meta.ogDescription || meta.description,
image: meta.ogImage || screenshotResponse, // use OG image or fallback to screenshot
favicon: meta.favicon,
url,
};
}
SEO Monitoring
// Check competitor pages periodically
async function monitorPage(url) {
const { data } = await extractData(url, 'metadata');
return {
title: data.title,
description: data.description,
h1Count: data.headings?.h1?.length || 0,
canonical: data.canonical,
ogImage: data.ogImage,
timestamp: new Date().toISOString(),
};
}
Screenshot API Comparison
How does SnapAPI compare to alternatives?
| Feature | SnapAPI | ScreenshotOne | Urlbox | ApiFlash |
|---|---|---|---|---|
| Free Tier | 100/month | 100/month | None | 100/month |
| Screenshot | ✅ | ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ | ❌ | |
| Video | ✅ | ❌ | ❌ | ❌ |
| Data Extract | ✅ | ❌ | ❌ | ❌ |
| AVIF Format | ✅ | ❌ | ❌ | ❌ |
| Cookie Blocking | ✅ | ✅ | ✅ | ❌ |
| Device Presets | 26+ | 10+ | 15+ | 5 |
| Starting Price | $9/mo | $29/mo | $99/mo | $29/mo |
SnapAPI is the only API that combines screenshots, PDFs, video recording, and data extraction in a single service — so you don't need four different API subscriptions.
Error Handling Tips
Always handle errors gracefully:
async function safeScreenshot(url) {
try {
const response = 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({ url, format: 'png', timeout: 30000 }),
});
if (response.status === 429) {
// Rate limited — wait and retry
await new Promise(r => setTimeout(r, 2000));
return safeScreenshot(url);
}
if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}
return Buffer.from(await response.arrayBuffer());
} catch (err) {
console.error(`Screenshot failed for ${url}:`, err.message);
return null;
}
}
Wrapping Up
Screenshot APIs save you from the headless browser nightmare. Instead of managing Puppeteer, Chrome dependencies, and memory issues, you get a simple REST API that handles everything.
SnapAPI stands out because it's four tools in one:
- 📸 Screenshots — PNG, JPEG, WebP, AVIF with 26+ device presets
- 📄 PDFs — A4, Letter, custom margins, headers/footers
- 🎬 Videos — Record browsing sessions (unique feature)
- 📊 Extract — Pull structured data, markdown, metadata from any page
Try It Free
Get 200 free screenshots per month at snapapi.pics. No credit card required.
The API is live and ready to use. If you run into any issues, the docs cover every parameter and edge case.
What screenshot use case are you building? Drop a comment below — I'd love to hear about it!
Top comments (0)