Ahmad Faraz

Senior Frontend Developer

Capture Webpage Screenshots with Next.js

Introduction In this guide, we’ll create a Next.js API that takes a webpage URL and generates a PNG screenshot using puppeteer and chrome-aws-lambda. This setup is optimized for both local and serverless environments. Prerequisites Step 1: Set Up Your Next.js Project Run the following commands to create a new Next.js app and install…

Introduction

In this guide, we’ll create a Next.js API that takes a webpage URL and generates a PNG screenshot using puppeteer and chrome-aws-lambda. This setup is optimized for both local and serverless environments.

Prerequisites

  • Basic understanding of Next.js
  • Node.js installed on your system

Step 1: Set Up Your Next.js Project

Run the following commands to create a new Next.js app and install necessary packages:

npx create-next-app@latest capture-image-app
cd capture-image-app
npm install puppeteer puppeteer-core chrome-aws-lambda busboy

Step 2: Create the API Route

In pages/api folder, create a file named generate-png.ts and add this code:

import { NextApiRequest, NextApiResponse } from "next";
import busboy from "busboy";
import chromium from "chrome-aws-lambda";
import puppeteerCore from "puppeteer-core";
import puppeteer from "puppeteer";

const puppeteerModule = process.env.NODE_ENV === "production" ? puppeteerCore : puppeteer;

export const config = { api: { bodyParser: false } };

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== "POST") return res.status(405).end("Method Not Allowed");

  const bb = busboy({ headers: req.headers });
  let htmlContent = "";

  bb.on("file", (_, file) => {
    file.on("data", (data) => htmlContent += data.toString());
  });

  bb.on("finish", async () => {
    const browser = await puppeteerModule.launch({
      args: ["--no-sandbox"],
      executablePath: process.env.NODE_ENV === "production" ? await chromium.executablePath : undefined,
      headless: true,
    });

    const page = await browser.newPage();
    await page.setContent(htmlContent, { waitUntil: "networkidle0" });

    const screenshot = await page.screenshot({ type: "png" });

    await browser.close();

    res.setHeader("Content-Type", "image/png");
    res.setHeader("Content-Disposition", "attachment; filename=screenshot.png");
    res.end(screenshot);
  });

  req.pipe(bb);
}

Step 3: Build the Frontend

Create a form that captures the screenshot:

import { useState } from "react";

export default function CaptureComponent() {
  const [isLoading, setLoading] = useState(false);

  async function captureScreenshot() {
    setLoading(true);
    const response = await fetch("/api/generate-png", { method: "POST" });
    const blob = await response.blob();
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = "screenshot.png";
    link.click();
    setLoading(false);
  }

  return (
    <div>
      <h2>Capture Screenshot</h2>
      <button onClick={captureScreenshot} disabled={isLoading}>
        {isLoading ? "Capturing..." : "Capture"}
      </button>
    </div>
  );
}

Conclusion

You’ve successfully built a webpage screenshot tool using Next.js and Puppeteer. This method works in both local and serverless environments, providing a scalable way to capture images from web pages.

One response to “Capture Webpage Screenshots with Next.js”

Leave a reply to Kevin Hurdle Cancel reply