DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

Puppeteer screenshot API alternative: Drop-in REST replacement

Puppeteer screenshot API alternative: Drop-in REST replacement

Your Node.js app runs Puppeteer in production. It works... until it doesn't.

Wednesday 2 AM: Out of memory. Chrome process crashed. Screenshots time out. Your monitoring hits PagerDuty. You spend the next 3 hours restarting services, tuning ulimits, and wondering why you're managing a headless browser at scale.

By Friday: you're looking for an alternative.

There is one. A REST API that replaces Puppeteer entirely. No server to manage. No Chrome crashes. No Docker complexity. Just HTTP requests.

Why Puppeteer breaks in production

Puppeteer works great locally. In production, it's fragile:

  • Memory leaks — Browser pools grow unbounded. ulimit -n exhausted. Process OOM kills.
  • Chrome crashes — Network blips, malformed pages, sandboxing issues kill the browser. No graceful recovery.
  • Scaling headaches — Each instance needs 500MB+ RAM for a browser pool. Vertical scaling hits hardware limits.
  • Maintenance burden — Chrome versions change. Tests break. Security patches require deployments.
  • Debugging nightmare — Timeouts happen silently. Errors are cryptic. Root cause takes hours to find.
  • Cold start latency — First screenshot takes 8-15 seconds (browser startup). Unacceptable for user-facing features.

Teams end up with:

  • Dedicated screenshot servers (EC2 instances just for Puppeteer)
  • Complex orchestration (Kubernetes, health checks, auto-scaling)
  • Alert fatigue (constant Chrome crashes)
  • Performance tax (15s+ per screenshot)

Or they give up on screenshot features entirely.

Solution: Hosted REST API

Instead of managing Puppeteer, call an API:

curl -X POST https://api.pagebolt.dev/take_screenshot \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "url": "https://example.com",
    "format": "png"
  }'

# Response: PNG binary immediately
Enter fullscreen mode Exit fullscreen mode

No infrastructure. No servers. No Chrome to manage. Just HTTP.

Before and after: Puppeteer vs PageBolt

Before: Puppeteer in Node.js

// Somewhere in your codebase...

const puppeteer = require('puppeteer');

let browser;

// Start browser on app startup
async function initBrowser() {
  browser = await puppeteer.launch({
    headless: true,
    args: [
      '--no-sandbox',
      '--disable-dev-shm-usage', // Prevent OOM
      '--disable-gpu',
      '--single-process' // Dangerous but sometimes necessary
    ]
  });
}

app.get('/screenshot', async (req, res) => {
  try {
    const page = await browser.newPage();

    // Set viewport (mobile, desktop, tablet?)
    await page.setViewport({ width: 1280, height: 720 });

    // Navigate with timeout
    await page.goto(req.query.url, { 
      waitUntil: 'networkidle2',
      timeout: 30000
    });

    // Take screenshot
    const screenshot = await page.screenshot({ 
      format: 'png',
      fullPage: false
    });

    await page.close();

    res.set('Content-Type', 'image/png');
    res.send(screenshot);
  } catch (error) {
    console.error('Screenshot failed:', error);
    res.status(500).send('Screenshot failed: ' + error.message);
  }
});

// Handle browser crashes
process.on('SIGTERM', async () => {
  await browser.close();
  process.exit(0);
});

// Restart browser if it crashes
setInterval(async () => {
  if (!browser || !browser.isConnected()) {
    console.error('Browser disconnected. Reconnecting...');
    browser = await puppeteer.launch({...});
  }
}, 60000);
Enter fullscreen mode Exit fullscreen mode

Cost of this approach:

  • 1 EC2 instance for Puppeteer: ~$50/month
  • DevOps time to manage/monitor: 5+ hours/month
  • Latency per screenshot: 8-15 seconds (cold start)
  • Reliability: 99% uptime if you're lucky
  • Scale: Can't handle 1000+ screenshots/day without vertical scaling

After: PageBolt REST API

const axios = require('axios');

const PAGEBOLT_API_KEY = process.env.PAGEBOLT_API_KEY;

app.get('/screenshot', async (req, res) => {
  try {
    const response = await axios.post(
      'https://api.pagebolt.dev/take_screenshot',
      {
        url: req.query.url,
        format: 'png'
      },
      {
        headers: {
          'Authorization': `Bearer ${PAGEBOLT_API_KEY}`,
          'Content-Type': 'application/json'
        },
        responseType: 'arraybuffer'
      }
    );

    res.set('Content-Type', 'image/png');
    res.send(response.data);
  } catch (error) {
    res.status(500).send('Screenshot failed: ' + error.message);
  }
});
Enter fullscreen mode Exit fullscreen mode

Cost of this approach:

  • API subscription: $29-99/month
  • DevOps overhead: 0 hours (no infrastructure)
  • Latency per screenshot: 2-3 seconds (API call only)
  • Reliability: 99.9% uptime (managed service)
  • Scale: Unlimited (no instance limits)

Real-world comparison

Factor Puppeteer PageBolt
Setup time 2-3 hours 10 minutes
Monthly cost $50+ infra + DevOps time $29-99 API
Latency 8-15s (cold start) 2-3s (API only)
Reliability 99% (if lucky) 99.9%
Scaling Vertical (hit ceiling) Infinite
Memory per instance 500MB+ for browser ~50MB (just HTTP)
Chrome crashes Frequent Never (managed)
Maintenance 5+ hours/month 0 hours

Migration: Puppeteer to PageBolt

Step 1: Get API key (2 minutes)
Sign up at pagebolt.dev. Get your Bearer token.

Step 2: Replace screenshot function (5 minutes)

// Old Puppeteer code
const screenshot = await browser.newPage().goto(url).screenshot();

// New PageBolt code
const response = await fetch('https://api.pagebolt.dev/take_screenshot', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${PAGEBOLT_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ url })
});
const screenshot = await response.arrayBuffer();
Enter fullscreen mode Exit fullscreen mode

Step 3: Test in staging (15 minutes)
Run your existing test suite. Screenshots should work identically.

Step 4: Deploy (30 minutes)
Push to production. Monitor for 1 hour. Done.

Step 5: Remove Puppeteer (optional, immediate savings)

npm uninstall puppeteer
# Saves 300MB of dependencies
# Removes 500MB+ runtime memory per process
Enter fullscreen mode Exit fullscreen mode

What you get

No infrastructure

  • No EC2 instances
  • No scaling complexity
  • No DevOps headaches

Fast

  • 2-3 seconds per screenshot (vs 8-15s with Puppeteer)
  • No cold start penalty

Reliable

  • 99.9% uptime SLA
  • Automatic failover
  • Managed by a dedicated team

Scalable

  • Take 1 screenshot or 10,000/day
  • Same cost, no performance degradation

Low cost

  • $29/month (5,000 requests/month)
  • vs $50+ infrastructure + DevOps time

Common questions

Q: Does it work with authentication?
Yes. Pass cookies or auth headers in the request.

Q: Can I test against staging/localhost?
Yes, if your staging is accessible from the internet. Localhost won't work (we're a hosted service).

Q: What about JavaScript rendering?
Full Chromium rendering. Waits for network idle by default. Fully configurable.

Q: Is there a free tier?
Yes. 100 screenshots/month, no credit card. Upgrade anytime.

The real cost of maintaining Puppeteer

Developers often overlook the hidden cost:

  • 5+ hours/month DevOps time
  • On-call stress (browser crashes at 2 AM)
  • Delayed features (time spent firefighting instead of building)
  • Performance tax (15s per screenshot, users wait)

PageBolt handles all of it. You get back the time spent managing infrastructure.

Getting started

  1. Sign up at pagebolt.dev (free: 100 requests/month)
  2. Get your API key (1 minute)
  3. Replace your Puppeteer code (5 lines)
  4. Deploy and monitor (30 minutes)

If you're running Puppeteer in production, you're already paying the cost — in infrastructure, DevOps time, and on-call stress.

Let PageBolt handle it.

Start free — 100 screenshots/month, no credit card.

Top comments (0)