How to Capture Screenshots of Any Website Using Node.js (Without Managing Puppeteer)
You need to screenshot a website from Node.js. Your options:
- Roll your own: Install Puppeteer, manage a browser process, handle memory leaks, debug timing issues when pages don't fully load, restart the process when Chrome crashes.
- Use an API: One function call. Done.
Most Node.js developers reach for Puppeteer because it's free and self-hosted. But in production, it's a tax: memory bloat, process restarts, CI timeouts, and the constant question of "why did this screenshot come back blank?"
Here's how to pick the right approach — and how to implement both.
The Puppeteer Way (DIY)
This is what you'd build:
const puppeteer = require('puppeteer');
async function screenshotSite(url) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Set viewport to match a desktop screen
await page.setViewport({ width: 1280, height: 720 });
// Navigate and wait for content to load
await page.goto(url, { waitUntil: 'networkidle2' });
// Take the screenshot
const screenshot = await page.screenshot({ path: 'output.png' });
await browser.close();
return screenshot;
}
screenshotSite('https://example.com');
This works. But in production:
- Memory: A single browser instance consumes 100–300MB. Five concurrent requests = 1.5GB. Scale to 50 concurrent = you're renting a bigger server.
- Crashes: Chrome occasionally crashes, especially under memory pressure. Your code needs retry logic.
-
Timing:
waitUntil: 'networkidle2'waits for all network activity to settle. On ad-heavy sites, this can timeout waiting for third-party analytics that never complete. - Scaling: Each Node.js process can only spawn so many browsers before the OS runs out of file descriptors. Multi-process orchestration is complex.
Cost: Hosting the Puppeteer setup yourself on AWS EC2 t3.large (2GB RAM) = ~$80–150/month. Scale to production throughput = $500–1,500/month just for the compute.
The API Way (3 Lines)
const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}` },
body: JSON.stringify({ url: 'https://example.com', width: 1280, height: 720 })
});
const buffer = await response.arrayBuffer();
That's it. No browser to manage. No memory to monitor. No timeouts to debug.
What you get:
- Screenshot returns in 2–5 seconds on average
- Handles slow sites, ads, third-party embeds — we wait for the page to stabilize, not for every network request
- 25+ device presets (iPhone 14, iPad Pro, MacBook, Galaxy S24, etc.) — just change the
deviceparameter - Optional features: block ads, remove cookie banners, take full-page screenshots, dark mode, custom cookies
- Automatic retry on failure — no flaky builds
Cost: Free tier = 100 requests/month. Paid from $29/month ($0.05 per 100 requests at scale).
When to Use Each
Use Puppeteer if:
- You're taking < 100 screenshots/month and don't want external dependencies
- Your infrastructure team has already optimized Puppeteer deployments
- You need local control and don't care about maintenance burden
Use an API if:
- You're taking > 100 screenshots/month (breaks even on cost vs server)
- You need to scale without managing infrastructure
- You want reliable screenshots without debugging timeouts
- Your team has limited DevOps capacity
Getting Started with an API
- Sign up: pagebolt.dev (free tier, no credit card)
- Grab your API key from settings
- Use it:
const https = require('https');
const payload = JSON.stringify({
url: 'https://example.com',
width: 1280,
height: 720
});
const options = {
hostname: 'api.pagebolt.dev',
path: '/v1/screenshot',
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json',
'Content-Length': payload.length
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
// data is your PNG buffer
console.log('Screenshot captured');
});
});
req.write(payload);
req.end();
Or with fetch (cleaner):
const image = await fetch('https://api.pagebolt.dev/v1/screenshot', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
width: 1280,
height: 720,
format: 'png'
})
}).then(r => r.arrayBuffer());
Common Use Cases
E-commerce product previews — Screenshot product pages, generate social cards, detect broken layouts before launch.
Marketing automation — Auto-generate email preview thumbnails, newsletter headers, or competitor tracking screenshots on a schedule.
QA/Testing — Baseline visual regression testing without spinning up a test lab.
Documentation — Auto-generate screenshots of your API docs, tutorials, or live examples.
Monitoring — Screenshot your production app on a schedule, diff against yesterday's baseline, alert on changes.
Next Steps
- Free tier: pagebolt.dev — 100 requests/month, no credit card
- Docs: pagebolt.dev/docs — full API reference, device presets, advanced options
- Pricing: pagebolt.dev/pricing — transparent, pay-as-you-go from $29/month
Stop managing Puppeteer in production. Try it free.
Top comments (0)