Menu
nodejstutorialscreenshots

How to Take Website Screenshots in Node.js (3 Methods)

SnapSharp Team·March 26, 2026·7 min read

How to Take Website Screenshots in Node.js

Node.js is the most popular runtime for server-side screenshot capture. This guide covers three approaches — Playwright, Puppeteer, and the SnapSharp API — with production-ready code for each.

Method 1: Playwright

Playwright is the modern standard for browser automation. It supports Chromium, Firefox, and WebKit from a single API.

Installation

npm install playwright
npx playwright install chromium

Basic Screenshot

import { chromium } from "playwright";

async function screenshot(url: string, output: string = "screenshot.png") {
  const browser = await chromium.launch();
  const page = await browser.newPage({
    viewport: { width: 1280, height: 720 },
  });
  await page.goto(url, { waitUntil: "networkidle" });
  await page.screenshot({ path: output });
  await browser.close();
}

await screenshot("https://example.com");

Full-Page Screenshot

await page.screenshot({ path: "full.png", fullPage: true });

Dark Mode

const page = await browser.newPage({
  viewport: { width: 1280, height: 720 },
  colorScheme: "dark",
});

Element Screenshot

const hero = page.locator(".hero-section");
await hero.screenshot({ path: "hero.png" });

PDF Export

await page.pdf({
  path: "page.pdf",
  format: "A4",
  printBackground: true,
});

Pros and Cons

Pros: Modern API, great TypeScript support, cross-browser, excellent auto-wait, active development by Microsoft.

Cons: ~150 MB browser download, ~200 MB RAM per instance, you handle concurrency, Chrome updates can break things.


Method 2: Puppeteer

Puppeteer is Google's Chrome automation library. It's been around since 2017 and has the largest ecosystem of plugins and tutorials.

Installation

npm install puppeteer

Puppeteer downloads Chromium automatically during install.

Basic Screenshot

import puppeteer from "puppeteer";

async function screenshot(url: string, output: string = "screenshot.png") {
  const 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: "networkidle2" });
  await page.screenshot({ path: output });
  await browser.close();
}

await screenshot("https://example.com");

Full-Page Screenshot

await page.screenshot({ path: "full.png", fullPage: true });

Block Requests (Ad Blocking)

await page.setRequestInterception(true);
page.on("request", (req) => {
  const blocked = ["ads", "analytics", "tracking"];
  if (blocked.some((b) => req.url().includes(b))) {
    req.abort();
  } else {
    req.continue();
  }
});

Wait for Specific Element

await page.goto(url);
await page.waitForSelector(".content-loaded", { timeout: 10_000 });
await page.screenshot({ path: output });

Pros and Cons

Pros: Huge ecosystem, Google-maintained, well-documented, works in Docker easily.

Cons: Chrome-only (no Firefox/WebKit), older API design, lacks Playwright's auto-wait, slightly higher memory usage.


Method 3: SnapSharp API

The SnapSharp API renders pages in the cloud and returns images over HTTP. No local browser needed — works in serverless functions, edge runtimes, and CI/CD.

Installation

npm install snapsharp

Basic Screenshot (SDK)

import { SnapSharp } from "snapsharp";

const snap = new SnapSharp(process.env.SNAPSHARP_API_KEY!);

const image = await snap.screenshot("https://example.com", {
  width: 1280,
  height: 720,
});
await Bun.write("screenshot.png", image);
// Or in Node: fs.writeFileSync("screenshot.png", Buffer.from(image));

Basic Screenshot (fetch)

const response = await fetch(
  "https://api.snapsharp.dev/v1/screenshot?" +
    new URLSearchParams({
      url: "https://example.com",
      width: "1280",
      height: "720",
    }),
  {
    headers: { Authorization: `Bearer ${process.env.SNAPSHARP_API_KEY}` },
  }
);

const buffer = await response.arrayBuffer();

Full-Page + Dark Mode + WebP

const image = await snap.screenshot("https://example.com", {
  fullPage: true,
  darkMode: true,
  format: "webp",
  blockAds: true,
});

Use in Next.js API Route

// app/api/screenshot/route.ts
import { SnapSharp } from "snapsharp";

const snap = new SnapSharp(process.env.SNAPSHARP_API_KEY!);

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const url = searchParams.get("url");
  if (!url) return Response.json({ error: "url required" }, { status: 400 });

  const image = await snap.screenshot(url, {
    width: 1200,
    height: 630,
    format: "png",
  });

  return new Response(image, {
    headers: {
      "Content-Type": "image/png",
      "Cache-Control": "public, max-age=86400",
    },
  });
}

Use in Express

import express from "express";
import { SnapSharp } from "snapsharp";

const app = express();
const snap = new SnapSharp(process.env.SNAPSHARP_API_KEY!);

app.get("/screenshot", async (req, res) => {
  const url = req.query.url as string;
  if (!url) return res.status(400).json({ error: "url required" });

  const image = await snap.screenshot(url, { width: 1280 });
  res.set("Content-Type", "image/png");
  res.send(Buffer.from(image));
});

app.listen(3000);

Batch Capture

const urls = [
  "https://example.com",
  "https://github.com",
  "https://vercel.com",
];

const results = await Promise.all(
  urls.map(async (url) => {
    const image = await snap.screenshot(url, { width: 1280 });
    const domain = new URL(url).hostname;
    const path = `${domain}.png`;
    await Bun.write(path, image);
    return path;
  })
);

Pros and Cons

Pros: Zero local dependencies, works in serverless/edge, elastic scaling, ad blocking and dark mode built-in, handles Chrome maintenance.

Cons: Network latency (~2–4s), costs at high volume (100 free/month), requires internet access.


Comparison Table

FeaturePlaywrightPuppeteerSnapSharp API
Install size~150 MB (browser)~150 MB (browser)~50 KB (SDK)
Local browserRequiredRequiredNot needed
Full-pageBuilt-inBuilt-inBuilt-in
Dark modecolorSchemeManual emulationdarkMode: true
Element captureBuilt-inManual clipselector param
PDF exportBuilt-inBuilt-inBuilt-in
Ad blockingRoute interceptionRequest interceptionblockAds: true
Cross-browserChromium, Firefox, WebKitChromium onlyChromium (managed)
Serverless-readyNo (binary too large)No (binary too large)Yes
RAM per capture~200 MB~250 MB0 (cloud)
Best forE2E testing, local toolsChrome-specific automationAPIs, serverless, SaaS

Which Should You Choose?

  • Playwright if you need cross-browser testing or local automation with the best modern API.
  • Puppeteer if you have existing Puppeteer code or need Chrome DevTools Protocol access.
  • SnapSharp API if you're building a production service and don't want to manage browser infrastructure.

All three produce identical screenshot quality for Chromium. The decision is about where the browser runs and who maintains it.

Get a free SnapSharp API key →