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.