DEV Community

Cover image for How to Take a Website Screenshot with Node.js
alekseykazandaev
alekseykazandaev

Posted on • Originally published at site-shot.com

How to Take a Website Screenshot with Node.js

If you are building link previews, monitoring dashboards, or visual testing tools in Node.js, a screenshot API gives you a clean HTTP-based workflow without browser orchestration. This version is tuned for the Dev.to audience and keeps the examples focused on the most common production use cases.

Prerequisites

  • Node.js 18+ (for built-in fetch) or any version with axios
  • A Site-Shot API key (sign up here)

Using Built-in Fetch (Node.js 18+)

const fs = require('fs');

async function captureScreenshot(url, outputPath = 'screenshot.png') {
  const params = new URLSearchParams({
    url,
    userkey: 'YOUR_API_KEY',
    width: '1280',
    height: '1024',
    format: 'png',
  });

  const response = await fetch(
    `https://api.site-shot.com/?${params.toString()}`
  );

  if (!response.ok) {
    throw new Error(`API returned ${response.status}`);
  }

  const buffer = Buffer.from(await response.arrayBuffer());
  fs.writeFileSync(outputPath, buffer);
  console.log(`Screenshot saved to ${outputPath}`);
}

captureScreenshot('https://example.com');
Enter fullscreen mode Exit fullscreen mode

Using Axios

const axios = require('axios');
const fs = require('fs');

async function captureScreenshot(url, outputPath = 'screenshot.png') {
  const response = await axios.get('https://api.site-shot.com/', {
    params: {
      url,
      userkey: 'YOUR_API_KEY',
      width: 1280,
      height: 1024,
      format: 'png',
    },
    responseType: 'arraybuffer',
    timeout: 70000,
  });

  fs.writeFileSync(outputPath, response.data);
  console.log(`Screenshot saved to ${outputPath}`);
}

captureScreenshot('https://example.com');
Enter fullscreen mode Exit fullscreen mode

Full Page Scrolling Screenshot

Capture the entire page, not just the viewport:

const params = new URLSearchParams({
  url: 'https://example.com',
  userkey: 'YOUR_API_KEY',
  full_size: '1',
  max_height: '15000',
  format: 'png',
});

const response = await fetch(
  `https://api.site-shot.com/?${params.toString()}`
);
Enter fullscreen mode Exit fullscreen mode

JSON Response with Base64

Get the screenshot as base64-encoded data along with HTTP metadata:

const params = new URLSearchParams({
  url: 'https://example.com',
  userkey: 'YOUR_API_KEY',
  width: '1280',
  height: '1024',
  format: 'png',
  response_type: 'json',
});

const response = await fetch(
  `https://api.site-shot.com/?${params.toString()}`
);
const data = await response.json();

if (data.error) {
  throw new Error(data.error);
}

// Remove data URL prefix if present
let base64 = data.image;
if (base64.includes(',')) {
  base64 = base64.split(',')[1];
}

const buffer = Buffer.from(base64, 'base64');
fs.writeFileSync('screenshot.png', buffer);
Enter fullscreen mode Exit fullscreen mode

Express.js Integration

Serve screenshots dynamically in an Express app:

const express = require('express');
const app = express();

app.get('/preview', async (req, res) => {
  const targetUrl = req.query.url;
  if (!targetUrl) {
    return res.status(400).send('Missing url parameter');
  }

  const params = new URLSearchParams({
    url: targetUrl,
    userkey: 'YOUR_API_KEY',
    width: '1280',
    height: '800',
    format: 'jpeg',
    scaled_width: '400',
  });

  const response = await fetch(
    `https://api.site-shot.com/?${params.toString()}`
  );

  if (!response.ok) {
    return res.status(502).send('Screenshot failed');
  }

  const buffer = Buffer.from(await response.arrayBuffer());
  res.set('Content-Type', 'image/jpeg');
  res.set('Cache-Control', 'public, max-age=3600');
  res.send(buffer);
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

This creates a /preview?url=https://example.com endpoint that returns a thumbnail screenshot — useful for link preview cards.

Capturing Multiple URLs

const urls = [
  'https://example.com',
  'https://wikipedia.org',
  'https://github.com',
];

const results = await Promise.all(
  urls.map(async (url) => {
    const params = new URLSearchParams({
      url,
      userkey: 'YOUR_API_KEY',
      width: '1280',
      height: '1024',
      format: 'png',
    });

    const response = await fetch(
      `https://api.site-shot.com/?${params.toString()}`
    );
    const buffer = Buffer.from(await response.arrayBuffer());
    const filename = url.replace(/https?:\/\//, '').replace(/\//g, '_') + '.png';
    fs.writeFileSync(filename, buffer);
    return filename;
  })
);

console.log('Saved:', results);
Enter fullscreen mode Exit fullscreen mode

The number of concurrent requests depends on your plan's dedicated worker count.

Summary

Parameter Description Example
url Target web page https://example.com
userkey Your API key abc123
width Viewport width (100–8000) 1280
height Viewport height (100–20000) 1024
full_size Capture full page 1
format Output format png or jpeg
response_type Response format image or json
scaled_width Resize output image 400

See the full API documentation and all code samples for more details.


Try Site-Shot free — no registration needed: https://www.site-shot.com/

Top comments (1)

Collapse
 
sleywill_45 profile image
Alex Serebriakov

solid walkthrough. puppeteer works great locally but the moment you deploy you're dealing with missing fonts, chromium crashes, memory limits...

been using snapapi.pics for hosted screenshot needs — REST API, returns image or base64, no headless browser to manage