Next.js is a full-stack framework based on React and its ecosystem.
All the mentioned code is stored in the Next.js screenshots example GitHub repository.
Your runtime matters
There are many ways to deploy and run Next.js, starting from a standalone application with Node.js runtime and ending with serverless on Vercel, Cloudflare, or similar platforms.
That means, for example, that you can not use Puppeteer easily on serverless platforms, because it will launch headless Chrome/Chromium, and highly likely it will miss dependencies and won’t just work.
Let’s quickly consider a few ways how to render website screenshots with Next.js depending on how you deploy it and run, it and your requirements.
An example application
I have built a simple Next.js application that demonstrates and compares approaches. It is just a simple form that asks for the URL of a website and then returns backs a screenshot.
The form submit handler:
The resulting application looks like:
Now, let’s try different approaches to rendering screenshots in Next.js and see what fits the best.
Puppeteer
Puppeteer is the most popular library in the Node.js ecosystem working with headless browsers. Another alternative can be Playwright, but Playwright is more about testing than a standalone browser automation library.
Next.js, Node.js and headless browsers
If you plan to deploy your Next.js application on a VPS with Linux or containerize with Docker and can run headless browsers, then it is pretty straightforward to implement.
Let’s install Puppeteer
first:
Now, let’s write a simple function to render screenshots with the Puppeteer
library. We will create an HTTP POST route handler in the app/api/screenshot/route.ts
file:
And then we will implement the Puppeteer rendering function in the lib/puppeteer.ts
file:
That’s it!
And don’t forget to add all the necessary Puppeteer dependencies to your Docker image.
The real problem arises when you want to run that on serverless, be it Cloudflare Workers or Vercel Edge functions. Then you can’t run Chrome/Chromium headless. You might solve some of the problems, but then you will memory limits and there is no end to that. But there is a way out—hosting and running headless browsers outside of your application or using a screenshot API.
Next.js, serverless and browsers in the cloud
In case you host Next.js on Vercel, or Cloudflare Workers or similar platform, there is a better solution. Either you can run headless browsers on a separate VPS and connect to them or you can use services like Browserless which run browsers for you.
The idea is simple. Since you can run headless browsers remotely either by yourself or using Browserless, you can connect to them via a simple WebSockets endpoint, and that’s the only thing you need to change in the code, except using the puppeteer-code
instead of puppeteer
, since you don’t need to download browsers anymore.
Cloudflare, by the way, has their own solution which you can use—Browser Rendering.
Using a screenshot API
But you don’t need to work with Puppeteer, headless browsers, and be worried about your runtime at all if… you choose to use a screenshot API.
The problem of rendering screenshots at scale while covering all the potential issues was solved a long time ago by screenshot APIs. As an example, I will use ScreenshotOne, but you can consider any other of the best screenshot APIs that also might fit you.
Let’s first integrate the API (lib/api.ts
):
Then update the route handler (app/api/screenshot/route.ts
):
That’s how simple it is when all that complexity is outsourced to an external application that cares of it for you.
The result is:
It is a bit different from the Puppeteer integration since ScreenshotOne uses the most popular viewport size 1920x1080
compared to the Puppeteer defaults.
By the way, a few bonuses you get when you use screenshot APIs instead of building your own solution:
- Blocking of cookie banners, ads, and other pop-ups.
- Custom fixes for different websites.
- Predictable pricing, not based on CPU and memory usage.
- Usually, screenshot APIs have support teams available for you and fix any issues you encounter.
- GPU rendering, videos if needed, lazy loading images for full pages, and many other features.
If you are curious, check out ScreenshotOne.
Summary
Choose whatever method suits you best. If you deploy Next.js with Node.js runtime, can run headless browsers, and don’t need to render a lot of screenshots, consider using classic Puppeteer.
But if you encounter issues, plan to scale, or don’t want to spend time on boring screenshot automation, you can go with a screenshot API like ScreenshotOne or choose one from the best screenshot APIs.