DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

How to Take a Screenshot of a Website with JavaScript

How to Take a Screenshot of a Website with JavaScript

You need a screenshot. You want to do it in JavaScript. No Puppeteer. No browser driver. Just a fetch call.

That's what this tutorial covers.

The Problem: Puppeteer Overhead

Typical Puppeteer approach in Node.js:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: ['--no-sandbox']
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({ path: 'screenshot.png' });
  await browser.close();
})();
Enter fullscreen mode Exit fullscreen mode

Issues:

  • 300MB+ dependency
  • Browser launch overhead (2-5 seconds)
  • Process management complexity
  • Fails in serverless (Lambda, Vercel Functions)
  • Version conflicts with system Chrome

The Solution: PageBolt API

One fetch call. PNG back.

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

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

Node.js: Save Screenshot to File

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

async function takeScreenshot(url, filename = 'screenshot.png') {
  const apiKey = process.env.PAGEBOLT_API_KEY;

  if (!apiKey) {
    throw new Error('PAGEBOLT_API_KEY environment variable not set');
  }

  const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: url,
      format: 'png',
      width: 1280,
      height: 720
    })
  });

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

  const buffer = await response.arrayBuffer();
  fs.writeFileSync(filename, Buffer.from(buffer));

  console.log(`✅ Screenshot saved: ${filename}`);
  console.log(`📊 Size: ${buffer.byteLength} bytes`);
}

// Usage
takeScreenshot('https://example.com', 'homepage.png');
Enter fullscreen mode Exit fullscreen mode

Setup:

# Set your API key
export PAGEBOLT_API_KEY=your-api-key-here

# Run the script
node screenshot.js
Enter fullscreen mode Exit fullscreen mode

Browser: Display Screenshot Inline

In the browser, fetch returns the binary PNG. Convert to base64 to display:

async function takeScreenshot(url) {
  const apiKey = 'your-pagebolt-api-key';

  const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: url,
      format: 'png',
      width: 1280,
      height: 720
    })
  });

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

  const buffer = await response.arrayBuffer();
  const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));

  // Display in image tag
  const img = document.createElement('img');
  img.src = `data:image/png;base64,${base64}`;
  document.body.appendChild(img);
}

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

React Component

import { useState } from 'react';

function ScreenshotCapture() {
  const [image, setImage] = useState(null);
  const [loading, setLoading] = useState(false);

  const handleScreenshot = async (e) => {
    e.preventDefault();
    const url = e.target.url.value;

    setLoading(true);
    try {
      const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.REACT_APP_PAGEBOLT_API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          url: url,
          format: 'png',
          width: 1280,
          height: 720
        })
      });

      const buffer = await response.arrayBuffer();
      const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));
      setImage(`data:image/png;base64,${base64}`);
    } catch (error) {
      console.error('Screenshot failed:', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <form onSubmit={handleScreenshot}>
        <input
          type="url"
          name="url"
          placeholder="https://example.com"
          required
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Taking screenshot...' : 'Take screenshot'}
        </button>
      </form>

      {image && <img src={image} alt="Screenshot" style={{ maxWidth: '100%' }} />}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Next.js API Route

// pages/api/screenshot.js

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { url } = req.body;

  if (!url) {
    return res.status(400).json({ error: 'URL required' });
  }

  try {
    const response = 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: url,
        format: 'png',
        width: 1280,
        height: 720
      })
    });

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

    const buffer = await response.arrayBuffer();

    res.setHeader('Content-Type', 'image/png');
    res.send(Buffer.from(buffer));
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
}
Enter fullscreen mode Exit fullscreen mode

Usage:

// In your Next.js client component
const response = await fetch('/api/screenshot', {
  method: 'POST',
  body: JSON.stringify({ url: 'https://example.com' })
});
const buffer = await response.arrayBuffer();
Enter fullscreen mode Exit fullscreen mode

Batch Screenshots

Screenshot multiple URLs in parallel:

async function batchScreenshots(urls) {
  const apiKey = process.env.PAGEBOLT_API_KEY;

  const promises = urls.map(url =>
    fetch('https://api.pagebolt.dev/v1/screenshot', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        url: url,
        format: 'png',
        width: 1280,
        height: 720
      })
    })
    .then(r => r.arrayBuffer())
    .then(buffer => {
      const filename = `screenshots/${new URL(url).hostname}.png`;
      fs.writeFileSync(filename, Buffer.from(buffer));
      return filename;
    })
  );

  const results = await Promise.all(promises);
  console.log(`✅ ${results.length} screenshots saved`);
}

// Usage
batchScreenshots([
  'https://example.com',
  'https://example.com/about',
  'https://example.com/pricing'
]);
Enter fullscreen mode Exit fullscreen mode

Device Emulation

Screenshot on mobile or tablet:

const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://example.com',
    format: 'png',
    viewportDevice: 'iphone_14_pro'  // 25+ devices available
  })
});

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

Error Handling

async function takeScreenshotSafe(url) {
  try {
    const response = 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: url }),
      timeout: 30000  // 30 second timeout
    });

    if (response.status === 401) {
      throw new Error('Invalid API key');
    }
    if (response.status === 429) {
      throw new Error('Rate limited. Upgrade your plan or wait.');
    }
    if (!response.ok) {
      throw new Error(`API error: ${response.status}`);
    }

    const buffer = await response.arrayBuffer();
    if (buffer.byteLength === 0) {
      throw new Error('Empty response from API');
    }

    return buffer;
  } catch (error) {
    console.error(`Screenshot failed: ${error.message}`);
    throw error;
  }
}
Enter fullscreen mode Exit fullscreen mode

Pricing

Free tier: 100 screenshots/month (covers development)
Starter: $29/month for 5,000 screenshots
Growth: $79/month for 25,000 screenshots
Scale: $199/month for 100,000 screenshots

For a web app that takes 1 screenshot per user session, the free tier covers ~3000 active users/month.

Real-World Use Cases

Website monitoring

Take daily screenshots to detect visual regressions:

const cron = require('node-cron');

cron.schedule('0 9 * * *', async () => {
  const screenshot = await takeScreenshot('https://mysite.com');
  // Compare with previous day's screenshot
  // Alert if significant visual change detected
});
Enter fullscreen mode Exit fullscreen mode

Social media preview generation

Generate preview images for shared links:

// When user shares a link, capture its visual appearance
const preview = await takeScreenshot(url);
// Store and use as og:image
Enter fullscreen mode Exit fullscreen mode

E-commerce product verification

Screenshot products after upload to verify rendering:

async function uploadProduct(productData) {
  // Save product to database
  const productUrl = `https://mystore.com/product/${productData.id}`;

  // Take screenshot to verify it rendered correctly
  const screenshot = await takeScreenshot(productUrl);

  // Store screenshot for visual QA
  await saveProductScreenshot(productData.id, screenshot);
}
Enter fullscreen mode Exit fullscreen mode

Environment Setup

Node.js:

export PAGEBOLT_API_KEY=your-api-key-here
node screenshot.js
Enter fullscreen mode Exit fullscreen mode

React (.env):

REACT_APP_PAGEBOLT_API_KEY=your-api-key-here
Enter fullscreen mode Exit fullscreen mode

Next.js (.env.local):

PAGEBOLT_API_KEY=your-api-key-here
Enter fullscreen mode Exit fullscreen mode

Next Steps

  1. Get a free PageBolt API key — 100 screenshots/month
  2. Copy one of the examples above (Node.js, React, Next.js, or browser)
  3. Set your API key as an environment variable
  4. Run it

Done. No Puppeteer. No browser driver. Just JavaScript + fetch.

Top comments (0)