How to capture screenshots of every page in a Next.js or Remix app without Puppeteer
Screenshot your full Next.js/Remix app from serverless functions or edge compute without managing Chromium. Works on Vercel, Netlify, and AWS Lambda.
You've built a Next.js or Remix app. Now you need to screenshot every page — for OG images, visual regression tests, or automated reports.
But Puppeteer requires Chromium, which weighs 300MB+ and won't run in Vercel edge functions, Lambda, or other serverless environments. You're stuck either running a separate server just for screenshots or skipping the feature entirely.
PageBolt solves this. It's an API — no local browser required. Call it from your serverless function, edge runtime, or anywhere in your app.
The problem with Puppeteer on Vercel
- Cold start timeout — Chromium takes 10-30 seconds to start. Edge functions timeout after 30 seconds total.
- Bundle size — Puppeteer + Chromium is 300MB+. Vercel functions have a 250MB limit.
- No local filesystem — Serverless functions can't write screenshots to disk, only to S3 or memory.
- Complexity — You need a separate service or a self-hosted server just for screenshots.
PageBolt is the serverless-native alternative.
Solution: PageBolt API
Call the PageBolt screenshot endpoint from your Next.js API route. It handles the browser, returns the image, done.
Next.js example
// pages/api/screenshot.js
import { NextResponse } from 'next/server';
const PAGEBOLT_API_KEY = process.env.PAGEBOLT_API_KEY;
export async function POST(request) {
const { url } = await request.json();
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': PAGEBOLT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: url,
width: 1200,
height: 630,
format: 'png',
}),
});
const data = await response.json();
// Return the screenshot as base64
return NextResponse.json({
screenshot: data.screenshot,
});
}
Remix example
// routes/api/screenshot.jsx
import { json } from '@remix-run/node';
const PAGEBOLT_API_KEY = process.env.PAGEBOLT_API_KEY;
export async function action({ request }) {
if (request.method !== 'POST') {
return json({ error: 'Method not allowed' }, { status: 405 });
}
const { url } = await request.json();
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': PAGEBOLT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: url,
width: 1200,
height: 630,
format: 'png',
}),
});
const data = await response.json();
return json({ screenshot: data.screenshot });
}
Batch screenshot all pages
If you need to screenshot every page in your app, generate a sitemap first, then batch the requests.
// lib/screenshot-all-pages.js
async function screenshotAllPages() {
// 1. Fetch your sitemap
const sitemapResponse = await fetch('https://yourapp.com/sitemap.xml');
const sitemapXml = await sitemapResponse.text();
// 2. Parse URLs
const urls = sitemapXml.match(/<loc>(.*?)<\/loc>/g).map(url =>
url.replace('<loc>', '').replace('</loc>', '')
);
// 3. Screenshot each URL (with concurrency limit)
const screenshots = [];
const concurrency = 5;
for (let i = 0; i < urls.length; i += concurrency) {
const batch = urls.slice(i, i + concurrency);
const results = await Promise.all(
batch.map(url =>
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: url,
width: 1200,
height: 630,
format: 'png',
}),
}).then(r => r.json())
)
);
screenshots.push(...results);
console.log(`Screenshotted ${i + batch.length}/${urls.length} pages`);
}
return screenshots;
}
Use cases
OG images on demand — Screenshot each product page, blog post, or user profile and use it as the OG image. No static generation, no design tool needed.
// pages/blog/[slug].jsx
import PageBolt from '@pagebolt/sdk';
export async function getServerSideProps({ params }) {
const pagebolt = new PageBolt(process.env.PAGEBOLT_API_KEY);
const screenshot = await pagebolt.screenshot({
url: `https://yourapp.com/api/og?slug=${params.slug}`,
width: 1200,
height: 630,
});
return {
props: { ogImage: screenshot },
};
}
Visual regression testing in CI — Screenshot your staging app, compare to production baseline.
// scripts/visual-regression.js (run on every deploy)
const baseline = await fetch('/screenshots/baseline.json');
const current = await screenshotAllPages();
const diffs = baseline.pages.map((page, i) => {
return pixelmatch(baseline[i].data, current[i].data, ...);
});
if (diffs.some(d => d > threshold)) {
console.error('Visual regression detected!');
process.exit(1);
}
Automated sitemaps with previews — Generate an HTML page listing all your app's routes with screenshot previews (great for internal dashboards).
Benefits over Puppeteer
| Feature | Puppeteer | PageBolt |
|---|---|---|
| Runs in Vercel edge | ❌ | ✅ |
| Bundle size | 300MB+ | 0 (API call) |
| Cold start | 10-30s | <2s |
| Authentication | Requires cookies/session management | Built-in session support |
| Parallel requests | Limited by CPU | Unlimited |
| Cost | Your infrastructure | Pay per screenshot |
Getting started
- Sign up at pagebolt.dev (free tier: 100 screenshots/month)
- Add
PAGEBOLT_API_KEYto your.env.local - Copy one of the examples above
- Screenshot all your pages
Try it free: 100 requests/month, no credit card required. Get started →
Need more control? Check out the full API docs → or reach out →
Get Started Free
100 requests/month, no credit card
One API key. Zero browser orchestration overhead in your agent's context window.
Get Your Free API Key →