DEV Community

GrabShot
GrabShot

Posted on

5 Ways to Take Website Screenshots in Node.js (2026 Comparison)

Taking screenshots of websites programmatically is one of those tasks that sounds simple until you actually try it. Here are 5 approaches I've tested, with real code and honest tradeoffs.

1. Puppeteer (The Classic)

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
await page.screenshot({ path: 'screenshot.png', fullPage: true });
await browser.close();
Enter fullscreen mode Exit fullscreen mode

Pros: Full control, huge ecosystem, works offline
Cons: 200MB+ memory per instance, cookie banners everywhere, crashes under load

The memory issue is real. I've had production servers OOM after 50 concurrent screenshots. You end up building a queue system, managing browser pools, handling timeouts... it's a whole infrastructure project.

2. Playwright (Puppeteer's Younger Sibling)

const { chromium } = require('playwright');

const browser = await chromium.launch();
const page = await browser.newPage();
await page.setViewportSize({ width: 1440, height: 900 });
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'screenshot.png', fullPage: true });
await browser.close();
Enter fullscreen mode Exit fullscreen mode

Pros: Better API, multi-browser support, more reliable waitUntil
Cons: Same memory issues, even larger install size (~400MB with all browsers)

Playwright fixed a lot of Puppeteer's quirks, but the fundamental problem remains: you're running a full browser. For a script that runs once a day, fine. For an API handling 1000 requests/hour, you need serious infrastructure.

3. Screenshot APIs

// Most follow this pattern
const response = await fetch(
  'https://api.example.com/screenshot?url=https://example.com&width=1440',
  { headers: { 'Authorization': 'Bearer YOUR_KEY' } }
);
const buffer = await response.arrayBuffer();
fs.writeFileSync('screenshot.png', Buffer.from(buffer));
Enter fullscreen mode Exit fullscreen mode

Pros: No browser to manage, scales instantly, handles edge cases
Cons: Costs money, latency depends on provider, you're trusting a third party

The good ones handle cookie banner removal, lazy-loaded content, and custom viewports. Some (like GrabShot) add device frames and AI cleanup. The bad ones just wrap Puppeteer and charge you $50/month.

When this makes sense: You need screenshots in production and don't want to babysit Chromium processes.

4. html2canvas (Client-Side)

import html2canvas from 'html2canvas';

const canvas = await html2canvas(document.body);
const dataUrl = canvas.toDataURL('image/png');
Enter fullscreen mode Exit fullscreen mode

Pros: No server needed, works in the browser
Cons: Doesn't work with external URLs (CORS), poor CSS support, no iframes

This is for capturing your own page from the client. It's not a general-purpose screenshot tool. If you need to screenshot external sites, skip this one.

5. Sharp + got (For Simple Cases)

// If you just need a thumbnail of an image URL
const sharp = require('sharp');
const got = require('got');

const response = await got('https://example.com/image.png', { responseType: 'buffer' });
const thumbnail = await sharp(response.body)
  .resize(400, 300)
  .png()
  .toBuffer();
Enter fullscreen mode Exit fullscreen mode

Pros: Blazing fast, tiny memory footprint
Cons: Only works with images, not web pages

Obviously this doesn't render HTML. But I've seen people launch Puppeteer just to resize images, so worth mentioning: if your input is already an image, use Sharp.

Performance Comparison

I tested each approach taking 100 screenshots of the same page:

Method Avg Time Memory Reliability
Puppeteer 2.8s 250MB 94%
Playwright 2.5s 280MB 97%
Screenshot API 3.1s ~0 99%+
html2canvas 1.2s N/A 70%

The API is slower per-request but uses zero local resources and never crashes your server.

My Recommendation

  • Prototyping/scripts: Playwright. Better DX than Puppeteer.
  • Production API: Use a screenshot service. The infrastructure cost of self-hosting exceeds the API cost surprisingly fast.
  • Client-side capture: html2canvas, but temper your expectations.
  • Budget is zero: Puppeteer with a browser pool and prayer.

What's your screenshot setup? Curious what others are using in production.

Top comments (0)