How to Capture Website Screenshots with an API in 2026
February 19, 2026 · 8 min read
Need to capture website screenshots programmatically? Whether you're building a link preview feature, generating OG images, or monitoring visual changes, there are several approaches. This guide covers all of them.
Option 1: Self-hosted with Puppeteer
Puppeteer is Google's Node.js library for controlling headless Chrome. It's the most common self-hosted approach:
const puppeteer = require('puppeteer');
async function screenshot(url) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 720 });
await page.goto(url, { waitUntil: 'networkidle0' });
const buffer = await page.screenshot({ type: 'png' });
await browser.close();
return buffer;
}
Pros: Free, full control, works offline.
Cons: You need to manage Chrome processes, handle crashes, deal with memory leaks, set up a server, handle timeouts, and maintain the infrastructure. Sites with anti-bot protection may block you.
Option 2: Self-hosted with Playwright
Playwright (by Microsoft) is similar to Puppeteer but supports Firefox and WebKit too:
const { chromium } = require('playwright');
async function screenshot(url) {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle' });
const buffer = await page.screenshot();
await browser.close();
return buffer;
}
Same trade-offs as Puppeteer. Slightly better API, but you still own the infrastructure.
Option 3: Use a Screenshot API
If you don't want to manage headless browsers, a hosted screenshot API handles everything for you. One HTTP request, one screenshot back.
Here's how it works with GrabShot:
cURL
curl "https://grabshot.dev/v1/screenshot?url=https://example.com&width=1280&height=720" \
-H "X-API-Key: your_api_key" \
-o screenshot.png
Node.js
const res = await fetch(
'https://grabshot.dev/v1/screenshot?url=https://example.com&width=1280',
{ headers: { 'X-API-Key': 'your_api_key' } }
);
const buffer = Buffer.from(await res.arrayBuffer());
fs.writeFileSync('screenshot.png', buffer);
Python
import requests
response = requests.get(
'https://grabshot.dev/v1/screenshot',
params={'url': 'https://example.com', 'width': '1280'},
headers={'X-API-Key': 'your_api_key'}
)
with open('screenshot.png', 'wb') as f:
f.write(response.content)
What Makes a Good Screenshot API?
When evaluating screenshot APIs, look for:
- Speed — How fast does it return screenshots? Under 3 seconds is good.
- Reliability — Does it handle JavaScript-heavy sites, SPAs, lazy loading?
- Device frames — Can you wrap screenshots in iPhone, MacBook, or browser frames?
- Full-page capture — Can it capture the entire scrollable page?
- Custom viewports — Width, height, device emulation, retina scaling.
- Caching — Does it cache identical requests to save you money?
- Pricing — Free tier for testing, reasonable paid plans.
Self-hosted vs API: When to Choose What
Use self-hosted Puppeteer/Playwright when:
- You need full control over the browser (extensions, cookies, auth)
- Volume is very high (10,000+ screenshots/day)
- You already have DevOps resources to maintain it
Use a screenshot API when:
- You want to ship fast without managing infrastructure
- You need extras like device frames, AI cleanup, or caching
- Reliability matters and you don't want to deal with Chrome crashes
- Your volume is moderate (up to a few thousand/month)
Try It Free
GrabShot offers 25 free screenshots per month with no credit card required. Features include device frames (iPhone, MacBook, browser chrome), AI-powered popup/banner removal, full-page capture, and custom viewports.
Compare Screenshot API Alternatives
Evaluating your options? See how GrabShot compares head-to-head: