How to Take Website Screenshots in Node.js
Three real ways to capture website screenshots in Node.js — from full headless browser control with Puppeteer and Playwright to a single API call with SnapRender. Here's the code for each, with the trade-offs explained honestly.
Puppeteer
Puppeteer is Google's official Node.js library for controlling headless Chrome. It downloads a compatible Chromium binary automatically, gives you full browser control, and has a massive community. It's the industry standard — but it's heavy.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800 });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.screenshot({ path: 'screenshot.png', fullPage: true });
await browser.close();
})();Watch out for:
- Downloads ~170MB Chromium binary on first install
- Chrome memory leaks in long-running processes
- Brutal cold starts in serverless environments (Lambda, Cloud Functions)
- Cloudflare and bot-protection sites will block headless Chrome
Playwright
Playwright is Microsoft's modern alternative. It supports Chromium, Firefox, and WebKit from a single API, auto-waits for content, and has native fullPage: true support. Cleaner API than Puppeteer, but same infrastructure overhead.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1280, height: 800 }
});
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png', fullPage: true });
await browser.close();
})();Better than Puppeteer, but still:
- ~400MB browser download on first install
- Multi-browser support adds complexity you may not need
- Same Cloudflare/bot-detection issues as Puppeteer
- Not serverless-friendly — cold starts exceed timeout limits
SnapRender API (one fetch call)
No browser to install, no binary to manage, no Chrome process to babysit. Send a POST request with the URL, get back the screenshot as binary. Works from any Node.js environment — serverless, containers, CI/CD, cron jobs.
const response = await fetch('https://api.snaprender.dev/v1/screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: 'https://example.com' })
});
const buffer = Buffer.from(await response.arrayBuffer());
require('fs').writeFileSync('screenshot.png', buffer);That's the entire working script. Uses the built-in fetch API available in Node.js 18+. Zero dependencies.
Full-page screenshots, custom viewports, JPEG quality
Most screenshot use cases need more than a basic viewport capture. Here's how to get a full-page screenshot at a specific resolution with JPEG compression:
const response = await fetch('https://api.snaprender.dev/v1/screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
full_page: true,
viewport: { width: 1440, height: 900 },
format: 'jpeg',
quality: 85
})
});| Parameter | Type | Description |
|---|---|---|
| full_page | boolean | Capture entire scrollable page, not just the viewport |
| viewport | object | Set width and height in pixels (default 1280x800) |
| format | string | "png" or "jpeg" (default png) |
| quality | integer | JPEG quality 1-100 (default 80, ignored for PNG) |
Express endpoint and S3 upload
Two common patterns: wrapping the screenshot in an Express route, and uploading the result to S3 for archival.
Screenshot as an Express endpoint
Build your own screenshot microservice in under 20 lines. Pass a URL as a query parameter and get the image streamed back.
const express = require('express');
const app = express();
app.get('/screenshot', async (req, res) => {
const { url } = req.query;
if (!url) return res.status(400).json({ error: 'url required' });
const response = await fetch('https://api.snaprender.dev/v1/screenshot', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SNAPRENDER_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ url, full_page: true })
});
const buffer = Buffer.from(await response.arrayBuffer());
res.set('Content-Type', 'image/png');
res.send(buffer);
});
app.listen(3000);Upload to S3
Capture and archive screenshots directly to an S3 bucket — useful for monitoring, compliance, or building a visual diff pipeline.
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
// 1. Take the screenshot
const response = await fetch('https://api.snaprender.dev/v1/screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: 'https://example.com' })
});
// 2. Upload to S3
const s3 = new S3Client({ region: 'us-east-1' });
await s3.send(new PutObjectCommand({
Bucket: 'my-screenshots',
Key: 'captures/example.png',
Body: Buffer.from(await response.arrayBuffer()),
ContentType: 'image/png'
}));Method comparison
| Feature | Puppeteer | Playwright | SnapRender |
|---|---|---|---|
| Setup time | 5-10 min | 5-10 min | 30 seconds |
| Dependencies | Chromium (~170MB) | Chromium (~400MB) | None (fetch) |
| Full-page | Yes | Yes | Yes |
| Cloudflare bypass | No | No | Yes |
| Serverless-ready | Difficult | Difficult | Yes |
| Cost | Free + infra | Free + infra | $9/mo for 1,500 |
Skip the browser setup
100 free screenshots per month. No Chromium to install. No credit card.
Get your API keyFrequently asked questions
The easiest way is using a screenshot API like SnapRender. It takes a single fetch call — no browser installation, no Puppeteer setup, no Chrome binary management required.
Playwright is generally better for new projects. It auto-waits for content, supports multiple browsers out of the box, and has a cleaner API. Puppeteer is more mature and has a larger ecosystem, but requires more manual wait logic.
Yes. Both Puppeteer and Playwright support fullPage: true in their screenshot methods. SnapRender supports full_page in the API request body. All three capture the entire scrollable page.
You need a headless browser. Puppeteer and Playwright both run real Chromium instances that execute JavaScript before capturing. SnapRender runs a managed browser in the cloud that waits for JS to finish.
Standard headless browsers get blocked by Cloudflare's bot detection. SnapRender has built-in Cloudflare bypass via FlareSolverr — add use_flaresolverr: true to your request.