If you've ever needed to capture website screenshots programmatically, you know the pain: spinning up Puppeteer, managing Chrome instances, handling timeouts, dealing with memory leaks. It's a whole infrastructure problem for what should be a simple task.
I built GrabShot to solve this. One API call, get a screenshot. Here's how it works.
The Simple Version
curl "https://grabshot.dev/v1/screenshot?url=https://github.com&format=png" \
-H "x-api-key: YOUR_KEY" \
-o github.png
That's it. You get back a PNG of github.com. No Puppeteer setup, no Chrome management, no memory leaks to debug at 3 AM.
Getting Started (Free Tier)
- Head to grabshot.dev/dashboard
- Create an account (just email)
- You get 25 free screenshots per month
- Start capturing
What Can You Actually Do With This?
OG Images for Your Blog
Generate dynamic Open Graph images so your links look great when shared:
const ogUrl = `https://grabshot.dev/v1/screenshot?url=${encodeURIComponent(myPageUrl)}&width=1200&height=630&format=png`;
Automated Testing
Capture screenshots of your staging environment before and after deploys:
const screenshot = await fetch(
`https://grabshot.dev/v1/screenshot?url=${stagingUrl}&width=1440&height=900`,
{ headers: { 'x-api-key': process.env.GRABSHOT_KEY } }
);
const buffer = await screenshot.arrayBuffer();
fs.writeFileSync(`screenshots/${Date.now()}.png`, Buffer.from(buffer));
Link Previews
Build rich link previews for your chat app or CMS:
async function getLinkPreview(url) {
const [meta, screenshot] = await Promise.all([
fetch(`https://metapeek.grabshot.dev/v1/extract?url=${encodeURIComponent(url)}`).then(r => r.json()),
fetch(`https://grabshot.dev/v1/screenshot?url=${encodeURIComponent(url)}&width=800&height=600`, {
headers: { 'x-api-key': API_KEY }
}).then(r => r.blob())
]);
return { title: meta.title, description: meta.description, image: screenshot };
}
Device Frames
Want the screenshot wrapped in a browser or phone frame? Add &frame=browser or &frame=iphone:
https://grabshot.dev/v1/screenshot?url=https://your-site.com&frame=browser&width=1440
API Parameters
| Parameter | Description | Default |
|---|---|---|
url |
Target URL (required) | - |
width |
Viewport width in pixels | 1440 |
height |
Viewport height in pixels | 900 |
format |
png, jpeg, or webp
|
png |
quality |
JPEG/WebP quality (1-100) | 80 |
frame |
Device frame: browser, iphone, ipad
|
none |
full_page |
Capture full scrollable page | false |
delay |
Wait ms before capture | 0 |
dark_mode |
Force dark mode | false |
Pricing
The free tier gives you 25 screenshots/month with a small watermark. Paid plans start at $9/month for 2,500 screenshots with no watermark, AI cleanup, and priority rendering.
Full pricing: grabshot.dev/#pricing
Node.js Quick Start
const GRABSHOT_KEY = process.env.GRABSHOT_KEY;
async function screenshot(url, options = {}) {
const params = new URLSearchParams({
url,
width: options.width || 1440,
height: options.height || 900,
format: options.format || 'png',
...options
});
const res = await fetch(`https://grabshot.dev/v1/screenshot?${params}`, {
headers: { 'x-api-key': GRABSHOT_KEY }
});
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
return Buffer.from(await res.arrayBuffer());
}
// Usage
const img = await screenshot('https://example.com', {
width: 1200,
frame: 'browser'
});
fs.writeFileSync('example.png', img);
Python Quick Start
import requests
def screenshot(url, api_key, **kwargs):
params = {"url": url, **kwargs}
headers = {"x-api-key": api_key}
r = requests.get("https://grabshot.dev/v1/screenshot", params=params, headers=headers)
r.raise_for_status()
return r.content
# Usage
img = screenshot("https://example.com", "YOUR_KEY", width=1200, format="png")
with open("example.png", "wb") as f:
f.write(img)
When to Use an API vs. Self-Hosting Puppeteer
Use an API when:
- You need screenshots occasionally (not millions/day)
- You don't want to manage Chrome/Puppeteer infrastructure
- You need reliable rendering across different sites
- You're building a feature, not a screenshot service
Self-host when:
- You need >100k screenshots/day
- You have specific browser extension requirements
- Latency under 500ms is critical
- You're building a screenshot service yourself
For most use cases, an API is the right call. You're paying $9-29/month instead of spending days on infrastructure that breaks when Chrome updates.
GrabShot is free to try. 25 screenshots/month, no credit card required. If you build something cool with it, I'd love to hear about it.
Top comments (0)