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 -nexhausted. 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
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);
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);
}
});
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();
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
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
- Sign up at pagebolt.dev (free: 100 requests/month)
- Get your API key (1 minute)
- Replace your Puppeteer code (5 lines)
- 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)