Forem

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

Puppeteer Alternative: Skip the Headless Chrome Setup and Use an API Instead

Puppeteer Alternative: Skip the Headless Chrome Setup and Use an API Instead

You know the problem. You need to take screenshots. So you reach for Puppeteer.

Two hours later, you're debugging:

  • Installation failures on your build server
  • Out-of-memory errors in production
  • Docker images that bloated to 800MB+
  • Browser crashes after 1,000 requests
  • Chromium version conflicts with your OS

Puppeteer is powerful. It's also exhausting to maintain.

There's a better way: use an API instead.

Why Puppeteer Hurts

Puppeteer is a Node.js library that controls a real Chrome browser. That power comes with a price.

1. Dependency Hell

Installing Puppeteer downloads Chromium (200MB+). On some systems, this fails:

  • ARM architectures (Raspberry Pi, M1 Macs) have spotty support
  • Corporate proxies block the download
  • CI/CD runners time out waiting for Chromium
  • Version conflicts with system libraries
npm install puppeteer
# [30 seconds later on a good day, hours on a bad one]
# Could fail silently if Chromium download fails
Enter fullscreen mode Exit fullscreen mode

2. Docker Bloat

To run Puppeteer in Docker, you need:

  • Base image: Node.js (200MB)
  • Chromium dependencies: libx11, libxss, etc. (300MB+)
  • Actual Chromium binary: (200MB)
  • Your app code: (5MB)

Total: 700MB-1GB per container.

FROM node:18
RUN apt-get update && apt-get install -y \
    libx11-6 libxss1 libappindicator1 libappindicator3-1 \
    libxext6 libxfont1 libxrender1 xfonts-encodings \
    fonts-liberation fonts-noto-color-emoji libasound2 \
    libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 libcups2 \
    libdbus-1-3 libgdk-pixbuf2.0-0 libgtk-3-0 libnspr4 \
    libnss3 libpango-1.0-0 libpangocairo-1.0-0 libxrandr2 xdg-utils
# ... 50 more lines
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode

PageBolt: no dependencies, 50MB image.

3. Memory Overhead

Each Puppeteer instance spins up a full Chrome process. On a t2.micro AWS instance:

  • Base memory: 100MB free
  • One Puppeteer browser: 80-150MB
  • Two browsers: you're swapping to disk

Scale this to 10 concurrent requests? You need a t3.large ($0.08/hour).

4. Maintenance Burden

Chromium updates frequently. Puppeteer occasionally breaks with new versions. You're now managing:

  • Chromium security patches
  • Browser crashes in production
  • Memory leaks in long-running processes
  • Flaky tests due to race conditions

The Puppeteer Code You're Writing

Here's a typical Puppeteer workflow to take a screenshot:

const puppeteer = require('puppeteer');

async function takeScreenshot(url) {
  let browser;
  try {
    // Launch browser (takes 2-5 seconds, consumes 100MB+)
    browser = await puppeteer.launch({
      headless: true,
      args: ['--no-sandbox', '--disable-setuid-sandbox']
    });

    // Create page
    const page = await browser.newPage();

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

    // Navigate (wait for network idle)
    await page.goto(url, { waitUntil: 'networkidle2' });

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

    return screenshot;
  } finally {
    if (browser) {
      await browser.close();
    }
  }
}

// Usage
takeScreenshot('https://example.com').then(data => {
  fs.writeFileSync('screenshot.png', data);
});
Enter fullscreen mode Exit fullscreen mode

Line count: 30+ lines. Time to first screenshot: 2-5 seconds. Memory usage: 100-200MB.


The PageBolt Alternative

Here's the same thing with PageBolt:

const response = await fetch('https://api.pagebolt.dev/take_screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ url: 'https://example.com' })
});

const { imageUrl } = await response.json();
console.log(imageUrl); // Direct download link, ready to use
Enter fullscreen mode Exit fullscreen mode

Line count: 10 lines. Time to first screenshot: 500ms. Memory usage: <1MB. Infrastructure: none.


Code Examples: Puppeteer vs PageBolt

Example 1: Simple Screenshot

Puppeteer (24 lines):

const puppeteer = require('puppeteer');

async function screenshot() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  const img = await page.screenshot({ fullPage: true });
  await browser.close();
  fs.writeFileSync('out.png', img);
}

screenshot();
Enter fullscreen mode Exit fullscreen mode

PageBolt (6 lines):

const res = await fetch('https://api.pagebolt.dev/take_screenshot', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer KEY' },
  body: JSON.stringify({ url: 'https://example.com' })
});
const { imageUrl } = await res.json();
console.log(imageUrl);
Enter fullscreen mode Exit fullscreen mode

Example 2: PDF Generation

Puppeteer (30 lines):

const puppeteer = require('puppeteer');

async function pdf() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.pdf({
    path: 'output.pdf',
    format: 'A4',
    margin: { top: '20px', bottom: '20px' }
  });
  await browser.close();
}

pdf();
Enter fullscreen mode Exit fullscreen mode

PageBolt (5 lines):

const res = await fetch('https://api.pagebolt.dev/generate_pdf', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer KEY' },
  body: JSON.stringify({ url: 'https://example.com' })
});
const { pdfUrl } = await res.json();
Enter fullscreen mode Exit fullscreen mode

Example 3: Using Axios

const axios = require('axios');

const response = await axios.post('https://api.pagebolt.dev/take_screenshot', {
  url: 'https://example.com',
  width: 1920,
  height: 1080
}, {
  headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
});

console.log(response.data.imageUrl);
Enter fullscreen mode Exit fullscreen mode

Example 4: Using curl

curl -X POST https://api.pagebolt.dev/take_screenshot \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "width": 1280,
    "height": 720
  }'

# Response: { "imageUrl": "https://cdn.pagebolt.dev/...", ... }
Enter fullscreen mode Exit fullscreen mode

Real Cost Comparison

Scenario 1: Static Screenshots (100/month)

Metric Puppeteer PageBolt
Setup time 2 hours 5 minutes
Code complexity 30+ lines 5 lines
Memory per request 100MB <1MB
Monthly cost $0 (self-hosted) $0 (free tier)
Infrastructure t3.micro ($10/mo) None
Time to first screenshot 2-5s 500ms
Maintenance burden High None

Scenario 2: 5,000 Screenshots/Month

Metric Puppeteer PageBolt
Server size needed t3.medium ($30/mo) None
Docker image size 800MB N/A
Code maintenance Ongoing None
API cost $0 $49
Total monthly cost $30 $49
Time to deploy 30 minutes 5 minutes
Reliability 95% (browser crashes) 99.9%

Puppeteer is cheaper until you factor in infrastructure, maintenance, and developer time.


When to Use Each

Use Puppeteer if:

  • ✅ You're testing a web app locally (dev environment only)
  • ✅ You need to interact with client-side JS in very specific ways
  • ✅ You have dedicated DevOps handling browser infrastructure
  • ✅ You're building a complex scraper with session management

Use PageBolt if:

  • ✅ You need screenshots/PDFs in production
  • ✅ You want zero infrastructure
  • ✅ You need fast, reliable responses (no browser crashes)
  • ✅ You care about code simplicity
  • ✅ You're scaling (cost scales better than Puppeteer)
  • ✅ You want Docker images under 100MB

Migration Path: Puppeteer → PageBolt

You don't need to rip out Puppeteer. You can migrate gradually:

Step 1: Replace Screenshot Logic

Replace all page.screenshot() calls with PageBolt API calls. Keep the rest of your Puppeteer code.

Step 2: Replace PDF Logic

Replace all page.pdf() calls with PageBolt API calls.

Step 3: Remove Puppeteer

Once screenshots and PDFs are gone, Puppeteer has nothing left to do. Uninstall it, save 200MB in your dependency graph.

npm uninstall puppeteer
# Your Docker image just got 600MB lighter
Enter fullscreen mode Exit fullscreen mode

Getting Started

Sign up free at pagebolt.dev — 100 requests/month, no credit card.

1. Get Your API Key

Create account → copy API key from dashboard.

2. Make Your First Request

curl -X POST https://api.pagebolt.dev/take_screenshot \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
Enter fullscreen mode Exit fullscreen mode

3. Integrate into Your App

Replace Puppeteer code with PageBolt API calls. Takes 5 minutes per integration point.


The Bottom Line

Puppeteer is powerful for local testing and complex automation. But for production screenshots and PDFs? You're paying a huge maintenance tax.

PageBolt gives you 95% of what you need for 5% of the complexity.

No dependency hell. No Docker bloat. No browser crashes. Just 5 lines of code.


Ready to ditch Puppeteer? Sign up free at pagebolt.dev — same power, zero infrastructure.

Top comments (0)