Updated February 2026 · 8 min read

How to Take Website Screenshots
with Node.js

There are three main approaches: run a headless browser yourself (Puppeteer/Playwright), use a managed API (GrabShot), or use a cloud browser service. Here's how each works, with code you can copy and paste.

1. Puppeteer (Self-Hosted)

Puppeteer controls a headless Chrome instance on your server. It's free and gives you full control, but you need to manage Chrome, memory, and scaling yourself.

npm install puppeteer
const puppeteer = require('puppeteer');

async function screenshot(url, outputPath) {
  const browser = await puppeteer.launch({
    headless: 'new',
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 900 });
  await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
  await page.screenshot({ path: outputPath, type: 'png' });
  await browser.close();
}

screenshot('https://github.com', 'github.png');

Pros: Free, full control, can interact with pages.
Cons: Uses 200-500MB RAM per browser instance. Crashes on high load. You handle scaling, timeouts, and zombie processes.

2. GrabShot API (Managed)

GrabShot runs the headless browser for you. One HTTP request returns a screenshot. No Chrome to manage, no server to maintain.

// No npm install needed - it's just an HTTP request

async function screenshot(url) {
  const apiKey = 'YOUR_API_KEY'; // Get free at grabshot.dev
  
  const response = await fetch(
    `https://grabshot.dev/v1/screenshot?` + new URLSearchParams({
      url,
      format: 'webp',
      width: '1440',
      apiKey
    })
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message);
  }
  
  return Buffer.from(await response.arrayBuffer());
}

// Usage
const img = await screenshot('https://github.com');
fs.writeFileSync('github.webp', img);

Pros: Zero infrastructure. Works from any environment (serverless, edge, CI). AI cleanup removes cookie banners. Device frame mockups built in.
Cons: 25 free/month, then $9/mo for 2,500.

Full-page + device frame example:

const url = `https://grabshot.dev/v1/screenshot?` + new URLSearchParams({
  url: 'https://stripe.com',
  fullPage: 'false',
  deviceFrame: 'macbook-air',
  aiCleanup: 'true',
  format: 'png',
  apiKey: 'YOUR_KEY'
});
// Returns a screenshot of Stripe inside a MacBook Air frame,
// with cookie banners and popups removed by AI

3. Playwright

Playwright is similar to Puppeteer but supports multiple browsers (Chrome, Firefox, WebKit) and has better auto-waiting.

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

async function screenshot(url, outputPath) {
  const browser = await chromium.launch();
  const page = await browser.newPage({
    viewport: { width: 1440, height: 900 }
  });
  
  await page.goto(url, { waitUntil: 'networkidle' });
  await page.screenshot({ path: outputPath, type: 'png' });
  await browser.close();
}

screenshot('https://github.com', 'github.png');

Pros: Multi-browser support, better waiting strategies, active development.
Cons: Same scaling challenges as Puppeteer. Larger install size (~400MB).

Comparison

Feature Puppeteer GrabShot API Playwright
Setup time5-30 min30 seconds5-30 min
Infrastructure neededServer with ChromeNoneServer with browsers
CostServer costsFree tier, then $9/moServer costs
Device framesDIYBuilt-inDIY
AI popup removalNoYesNo
Serverless friendlyDifficultYesDifficult
Page interactionFull controlLimitedFull control

See it in action

Try GrabShot right now — paste any URL and get a screenshot instantly. No signup needed.

Try Free Screenshot Tool →