DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

How to capture screenshots of any website using Node.js (without managing Puppeteer)

How to Capture Screenshots of Any Website Using Node.js (Without Managing Puppeteer)

You need to screenshot a website from Node.js. Your options:

  1. Roll your own: Install Puppeteer, manage a browser process, handle memory leaks, debug timing issues when pages don't fully load, restart the process when Chrome crashes.
  2. Use an API: One function call. Done.

Most Node.js developers reach for Puppeteer because it's free and self-hosted. But in production, it's a tax: memory bloat, process restarts, CI timeouts, and the constant question of "why did this screenshot come back blank?"

Here's how to pick the right approach — and how to implement both.

The Puppeteer Way (DIY)

This is what you'd build:

const puppeteer = require('puppeteer');

async function screenshotSite(url) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  // Set viewport to match a desktop screen
  await page.setViewport({ width: 1280, height: 720 });

  // Navigate and wait for content to load
  await page.goto(url, { waitUntil: 'networkidle2' });

  // Take the screenshot
  const screenshot = await page.screenshot({ path: 'output.png' });

  await browser.close();
  return screenshot;
}

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

This works. But in production:

  • Memory: A single browser instance consumes 100–300MB. Five concurrent requests = 1.5GB. Scale to 50 concurrent = you're renting a bigger server.
  • Crashes: Chrome occasionally crashes, especially under memory pressure. Your code needs retry logic.
  • Timing: waitUntil: 'networkidle2' waits for all network activity to settle. On ad-heavy sites, this can timeout waiting for third-party analytics that never complete.
  • Scaling: Each Node.js process can only spawn so many browsers before the OS runs out of file descriptors. Multi-process orchestration is complex.

Cost: Hosting the Puppeteer setup yourself on AWS EC2 t3.large (2GB RAM) = ~$80–150/month. Scale to production throughput = $500–1,500/month just for the compute.

The API Way (3 Lines)

const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}` },
  body: JSON.stringify({ url: 'https://example.com', width: 1280, height: 720 })
});

const buffer = await response.arrayBuffer();
Enter fullscreen mode Exit fullscreen mode

That's it. No browser to manage. No memory to monitor. No timeouts to debug.

What you get:

  • Screenshot returns in 2–5 seconds on average
  • Handles slow sites, ads, third-party embeds — we wait for the page to stabilize, not for every network request
  • 25+ device presets (iPhone 14, iPad Pro, MacBook, Galaxy S24, etc.) — just change the device parameter
  • Optional features: block ads, remove cookie banners, take full-page screenshots, dark mode, custom cookies
  • Automatic retry on failure — no flaky builds

Cost: Free tier = 100 requests/month. Paid from $29/month ($0.05 per 100 requests at scale).

When to Use Each

Use Puppeteer if:

  • You're taking < 100 screenshots/month and don't want external dependencies
  • Your infrastructure team has already optimized Puppeteer deployments
  • You need local control and don't care about maintenance burden

Use an API if:

  • You're taking > 100 screenshots/month (breaks even on cost vs server)
  • You need to scale without managing infrastructure
  • You want reliable screenshots without debugging timeouts
  • Your team has limited DevOps capacity

Getting Started with an API

  1. Sign up: pagebolt.dev (free tier, no credit card)
  2. Grab your API key from settings
  3. Use it:
const https = require('https');

const payload = JSON.stringify({
  url: 'https://example.com',
  width: 1280,
  height: 720
});

const options = {
  hostname: 'api.pagebolt.dev',
  path: '/v1/screenshot',
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
    'Content-Type': 'application/json',
    'Content-Length': payload.length
  }
};

const req = https.request(options, (res) => {
  let data = '';
  res.on('data', chunk => data += chunk);
  res.on('end', () => {
    // data is your PNG buffer
    console.log('Screenshot captured');
  });
});

req.write(payload);
req.end();
Enter fullscreen mode Exit fullscreen mode

Or with fetch (cleaner):

const image = await fetch('https://api.pagebolt.dev/v1/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://example.com',
    width: 1280,
    height: 720,
    format: 'png'
  })
}).then(r => r.arrayBuffer());
Enter fullscreen mode Exit fullscreen mode

Common Use Cases

E-commerce product previews — Screenshot product pages, generate social cards, detect broken layouts before launch.

Marketing automation — Auto-generate email preview thumbnails, newsletter headers, or competitor tracking screenshots on a schedule.

QA/Testing — Baseline visual regression testing without spinning up a test lab.

Documentation — Auto-generate screenshots of your API docs, tutorials, or live examples.

Monitoring — Screenshot your production app on a schedule, diff against yesterday's baseline, alert on changes.

Next Steps

  • Free tier: pagebolt.dev — 100 requests/month, no credit card
  • Docs: pagebolt.dev/docs — full API reference, device presets, advanced options
  • Pricing: pagebolt.dev/pricing — transparent, pay-as-you-go from $29/month

Stop managing Puppeteer in production. Try it free.

Top comments (0)