Back to Blog
Guide February 26, 2026 · 4 min read

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

Taking screenshots in Next.js usually means bundling Puppeteer or Playwright — and figuring out how to run Chromium on Vercel. Here's how to do it with a one-line fetch call and no browser dependency.

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' }
  });
}

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);

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);
}

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 }

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()));

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()));

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.

Get Started Free

100 requests/month, no credit card

Screenshots, PDFs, and video recordings from your Next.js app — no Chromium, no Puppeteer, no cold start issues.

Get Your Free API Key →