How to Take Screenshots in Node.js
Learn how to capture website screenshots in Node.js using ShotAPI, Puppeteer, and Playwright. Complete code examples included.
Published February 10, 2026
Three Approaches
| Approach | Best For | Complexity | Setup Time |
|---|---|---|---|
| ShotAPI | Simple screenshots, production apps | Low | 5 minutes |
| Puppeteer | Complex automation, private URLs | High | Hours |
| Playwright | Testing, multi-browser support | High | Hours |
Approach 1: ShotAPI (Recommended)
The simplest way to take screenshots. No infrastructure, no browser management, no headaches.
const fetch = require('node-fetch');
const fs = require('fs');
async function takeScreenshot(url) {
const apiUrl = `https://shotapi.io/api/screenshot?url=${encodeURIComponent(url)}&format=png`;
const response = await fetch(apiUrl, {
headers: {
'X-API-Key': process.env.SHOTAPI_KEY
}
});
if (!response.ok) {
throw new Error(`Failed: ${response.status}`);
}
const buffer = await response.buffer();
fs.writeFileSync('screenshot.png', buffer);
console.log('Screenshot saved!');
}
takeScreenshot('https://example.com'); Pros
- ✓ No dependencies to install (just node-fetch)
- ✓ No infrastructure to manage
- ✓ Works in serverless environments (Lambda, Vercel, etc.)
- ✓ 100 free screenshots per day
Approach 2: Puppeteer
Full browser automation. Use when you need complex interactions or screenshots behind authentication.
Install
npm install puppeteer Code
const puppeteer = require('puppeteer');
async function takeScreenshot(url) {
let browser;
try {
browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 720 });
await page.goto(url, { waitUntil: 'networkidle0' });
await page.screenshot({
path: 'screenshot.png',
type: 'png'
});
console.log('Screenshot saved!');
} finally {
if (browser) await browser.close();
}
}
takeScreenshot('https://example.com'); Pros & Cons
Pros
- ✓ Full browser automation
- ✓ Works with auth/VPN
- ✓ Inject custom JavaScript
Cons
- ✗ Complex setup
- ✗ High memory usage
- ✗ Ongoing maintenance
Approach 3: Playwright
Multi-browser automation framework. Best for testing and cross-browser screenshots.
Install
npm install @playwright/test Code
const { chromium } = require('@playwright/test');
async function takeScreenshot(url) {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url);
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
console.log('Screenshot saved!');
}
takeScreenshot('https://example.com'); Pros & Cons
Pros
- ✓ Multi-browser (Chrome, Firefox, Safari)
- ✓ Better for testing
- ✓ Modern API
Cons
- ✗ Large download (browsers)
- ✗ High memory usage
- ✗ Overkill for simple screenshots
When to Use Which
Use ShotAPI
- ✓ Production apps
- ✓ Serverless/Lambda
- ✓ Simple screenshots
- ✓ Public URLs
- ✓ No infrastructure
Use Puppeteer
- ✓ Complex automation
- ✓ Behind auth/VPN
- ✓ Custom JavaScript
- ✓ Scraping data
- ✓ Form interactions
Use Playwright
- ✓ E2E testing
- ✓ Multi-browser
- ✓ Cross-platform tests
- ✓ Visual regression
- ✓ Test automation
Production-Ready Error Handling
Here's a production-ready example with TypeScript and proper error handling:
import fetch from 'node-fetch';
import fs from 'fs/promises';
interface ScreenshotOptions {
url: string;
format?: 'png' | 'jpeg' | 'webp' | 'pdf';
width?: number;
height?: number;
fullPage?: boolean;
}
async function takeScreenshot(
options: ScreenshotOptions,
outputPath: string
): Promise<void> {
const params = new URLSearchParams({
url: options.url,
format: options.format || 'png',
...options.width && { width: options.width.toString() },
...options.height && { height: options.height.toString() },
...options.fullPage && { fullPage: 'true' },
});
const apiUrl = `https://shotapi.io/api/screenshot?${params}`;
try {
const response = await fetch(apiUrl, {
headers: {
'X-API-Key': process.env.SHOTAPI_KEY || '',
},
});
if (!response.ok) {
throw new Error(
`Screenshot failed: ${response.status} ${response.statusText}`
);
}
const buffer = await response.buffer();
await fs.writeFile(outputPath, buffer);
console.log(`Screenshot saved to ${outputPath}`);
} catch (error) {
console.error('Screenshot error:', error);
throw error;
}
}
// Usage
takeScreenshot(
{
url: 'https://example.com',
format: 'webp',
width: 1920,
height: 1080,
fullPage: true,
},
'screenshot.webp'
); Start Taking Screenshots in Node.js
Get your API key and start with 100 free screenshots per day.