DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

How to take screenshots in Next.js (without installing Chromium)

How to Take Screenshots in Next.js (Without Installing Chromium)

The standard approach for screenshots in a Next.js app is Puppeteer or Playwright — which means adding a headless browser to your dependency tree, figuring out how to run Chromium on Vercel or your serverless platform, and debugging cold start timeouts when the browser takes too long to spin up.

There's a simpler path: call a screenshot API from a Route Handler or API route. No browser, no Chromium, no deployment headaches.

App Router: Route Handler

// app/api/screenshot/route.js
import { NextResponse } from 'next/server';

export async function POST(request) {
  const { url } = await request.json();

  const res = 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,
      fullPage: true,
      blockBanners: true,
      format: 'png'
    })
  });

  const image = await res.arrayBuffer();

  return new NextResponse(image, {
    headers: { 'Content-Type': 'image/png' }
  });
}
Enter fullscreen mode Exit fullscreen mode

Call it from your frontend:

const res = await fetch('/api/screenshot', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://example.com' })
});
const blob = await res.blob();
const imageUrl = URL.createObjectURL(blob);
Enter fullscreen mode Exit fullscreen mode

Pages Router: API Route

// pages/api/screenshot.js
export default async function handler(req, res) {
  const { url } = req.body;

  const capture = 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, fullPage: true, blockBanners: true })
  });

  const image = Buffer.from(await capture.arrayBuffer());
  res.setHeader('Content-Type', 'image/png');
  res.send(image);
}
Enter fullscreen mode Exit fullscreen mode

Common options

// Capture a specific viewport size (e.g. mobile)
{ url, viewportDevice: 'iphone_14_pro' }

// Dark mode
{ url, darkMode: true, fullPage: true }

// Capture HTML instead of a URL (e.g. rendered React component)
{ html: '<html><body><h1>Hello</h1></body></html>' }

// JPEG with quality setting
{ url, format: 'jpeg', quality: 85 }
Enter fullscreen mode Exit fullscreen mode

Saving to disk (scripts / build tools)

For use in scripts, build tools, or CI:

import fs from 'fs';

const res = 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://yourapp.com', fullPage: true })
});

fs.writeFileSync('screenshot.png', Buffer.from(await res.arrayBuffer()));
Enter fullscreen mode Exit fullscreen mode

The upgrade: record a narrated walkthrough

Once you have screenshot infrastructure, adding video is the same API:

const res = await fetch('https://pagebolt.dev/api/v1/video', {
  method: 'POST',
  headers: { 'x-api-key': process.env.PAGEBOLT_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    steps: [
      { action: 'navigate', url: 'https://yourapp.com', note: 'Open the app' },
      { action: 'click', selector: '#demo', note: 'Try the demo' }
    ],
    audioGuide: {
      enabled: true,
      voice: 'nova',
      script: "Here's the app. {{1}} {{2}} Click to try it."
    },
    pace: 'slow'
  })
});
fs.writeFileSync('demo.mp4', Buffer.from(await res.arrayBuffer()));
Enter fullscreen mode Exit fullscreen mode

Same pattern as the screenshot — one fetch call, binary result, no browser process.

Vercel / serverless deployment

No special config needed. The screenshot API is an outbound HTTPS call — it runs fine in any serverless environment without Chromium layers, Docker configuration, or memory tuning.

Add your API key to environment variables in your Vercel project settings as PAGEBOLT_API_KEY and the route handler works out of the box.


Try it free — 100 requests/month, no credit card. → pagebolt.dev

Top comments (0)