Take Screenshots Programmatically in Node.js: One HTTP Call, No Puppeteer
Capture screenshots without installing Chromium or managing browser lifecycle. One fetch() call returns a PNG in under a second — batch, parallel, CI/CD-ready.
You need to take a screenshot in your Node.js app. The traditional approach: install Puppeteer, manage Chromium, write boilerplate code, handle browser lifecycle. It's slow and heavy.
PageBolt's /screenshot endpoint solves this. One HTTP call, one screenshot. No browser to manage, no dependencies beyond the built-in fetch API.
Why This Matters
Every Node.js developer eventually hits this need: screenshots for error reports, audit trails, thumbnail previews, or visual testing. With Puppeteer, you get:
- 300MB+ Chromium download per environment
- Browser startup: 2–5 seconds per screenshot
- Memory overhead: 200–500MB per instance
- Complex error handling and lifecycle management
With a screenshot API: one HTTP request, 500–800ms response, no dependencies, no memory overhead.
Basic Screenshot: One HTTP Call
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': process.env.PAGEBOLT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://example.com/dashboard',
width: 1440,
height: 900,
format: 'png',
}),
});
const imageBuffer = await response.arrayBuffer();
console.log(`Screenshot captured: ${imageBuffer.byteLength} bytes`);
The image is in memory, ready to save or send.
Save to Disk
import fs from 'fs';
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': process.env.PAGEBOLT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ url: 'https://example.com/dashboard', format: 'png' }),
});
const buffer = await response.arrayBuffer();
fs.writeFileSync('screenshot.png', Buffer.from(buffer));
console.log('Screenshot saved to screenshot.png');
Batch Screenshots (Sequential)
async function captureScreenshots(urls) {
const results = [];
for (const url of urls) {
try {
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: { 'x-api-key': process.env.PAGEBOLT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ url, format: 'webp', quality: 80 }),
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
const buffer = await response.arrayBuffer();
results.push({ url, size: buffer.byteLength, data: Buffer.from(buffer) });
console.log(`✓ ${url} (${buffer.byteLength} bytes)`);
} catch (error) {
console.error(`✗ ${url} failed: ${error.message}`);
results.push({ url, error: error.message });
}
}
return results;
}
const screenshots = await captureScreenshots([
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3',
]);
Each screenshot takes ~500–800ms. 10 screenshots ≈ 5–8 seconds total, with clean error handling.
Parallel Screenshots: Promise.all()
For faster batch processing, run all screenshots concurrently:
async function captureParallel(urls) {
const promises = urls.map(async (url) => {
try {
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: { 'x-api-key': process.env.PAGEBOLT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ url, format: 'webp', quality: 85, fullPage: true }),
});
const buffer = await response.arrayBuffer();
return { url, success: true, size: buffer.byteLength, data: Buffer.from(buffer) };
} catch (error) {
return { url, success: false, error: error.message };
}
});
return Promise.all(promises);
}
const results = await captureParallel([
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3',
]);
console.log(`✓ ${results.filter(r => r.success).length}/${results.length} captured`);
All 10 screenshots run in parallel: ~800ms total instead of 8 seconds.
CI/CD Integration: GitHub Actions
name: Screenshot Tests
on: [push, pull_request]
jobs:
screenshots:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Capture staging screenshot
env:
PAGEBOLT_API_KEY: ${{ secrets.PAGEBOLT_API_KEY }}
run: |
node -e "
const fs = require('fs');
fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: { 'x-api-key': process.env.PAGEBOLT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ url: 'https://staging.example.com/dashboard', format: 'png', width: 1440, height: 900 }),
}).then(r => r.arrayBuffer()).then(buf => {
fs.writeFileSync('screenshot.png', Buffer.from(buf));
console.log('Screenshot captured');
});
"
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: screenshots
path: screenshot.png
Captures a screenshot on every PR, zero infrastructure overhead — no Chromium installation step needed.
Full-Page and Mobile Screenshots
// Full page — auto-scrolls to capture all content
const fullPage = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: { 'x-api-key': process.env.PAGEBOLT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://example.com/landing',
fullPage: true,
fullPageScroll: true,
fullPageMaxHeight: 10000,
format: 'png',
}),
});
// iPhone 14 Pro emulation
const mobile = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: { 'x-api-key': process.env.PAGEBOLT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://example.com/landing',
viewportDevice: 'iphone_14_pro',
format: 'png',
}),
});
Error Handling
async function takeScreenshot(url) {
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: { 'x-api-key': process.env.PAGEBOLT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ url, format: 'png' }),
});
if (!response.ok) {
if (response.status === 401) throw new Error('Invalid API key');
if (response.status === 402) throw new Error('Monthly quota exceeded');
if (response.status === 429) throw new Error('Rate limit exceeded — retry shortly');
throw new Error(`API error: ${response.status}`);
}
return response.arrayBuffer();
}
Cost Comparison: API vs Puppeteer
| Metric | Puppeteer | PageBolt API |
|---|---|---|
| 1 screenshot | ~500ms cold start | 500–800ms |
| 100 screenshots/mo | $50–100 infra + dev time | $1–5 |
| 1,000 screenshots/mo | $200–500 + maintenance | $10–20 |
| Memory per screenshot | 200–500MB | ~1MB overhead |
| Setup time | 2+ hours + debugging | 5 minutes |
| Chromium management | Manual | Managed |
Getting Started
- Sign up — Free tier: 100 requests/month, no credit card
- Get your API key — Available immediately from the dashboard
- Test it — Copy the basic example above and run it locally
- Integrate — Use the async/await patterns in your app
- Scale — Monitor usage in the dashboard; upgrade if needed
Screenshots in Node.js don't require Puppeteer. Try PageBolt free — 100 screenshots/month, no credit card needed.
Add screenshots to your Node.js app — free
100 requests/month, no credit card. One fetch() call, no Puppeteer, no Chromium.