DEV Community

Cover image for Vercel + Puppeteer
Joel Griffith
Joel Griffith

Posted on

Vercel + Puppeteer

Vercel is the platform for frontend developers, providing the speed and reliability innovators need to create at the moment of inspiration. At the time of this writing, Vercel powers more than 35+ frameworks. For the purposes of this post, however, we’ll be mostly focusing on NextJS. Puppeteer is a NodeJS library that allows developers to programmatically control a web-browser. As of version 19, Puppeteer supports both Firefox and Chrome.

Combining these technologies is the task for today! We’ll use Puppeteer to generate a PDF of a website and Vercel.JS to host it. When done locally this is a pretty straightforward task, however, you'll likely run into a few issues regarding bundle size and memory limits once you deploy your project to Vercel’s cloud. Below we detail how you can get around these issues easily with browserless. If you want to see code right away, feel free to check out our example project here.

Best practices and setting up

  • We're using Next.JS as our main technology since it's incredibly effective and popular for Vercel deployments.
  • You should be somewhat familiar with how environment variables work in NextJS to properly store secrets. Feel free to read more here.
  • For the purpose of this blogpost we'll create a basic route that generates a PDF of a URL. Feel free to alter this, but it'll be enough to get you started!

Setting up Puppeteer for Vercel

To get started, create a new Next.js application through the CLI:



$ npx create-next-app@latest


Enter fullscreen mode Exit fullscreen mode

This command will create your basic "Hello World" app and then exit. For NextJS apps in particular, you'll likely have a "pages" directory with an "api" folder as well. This is where we'll be spending most of our time since our functionality is created inside the NodeJS environment.

Once your application is set up then we'll also install Puppeteer. We'll opt for the 'puppeteer-core' module to avoid the first issue in Vercel: the 50MB file-size limit. Puppeteer by default ships with headless Chrome bundled together, which is easily over 50MB in size. By using 'puppeteer-core' we can get around this by only having puppeteer's code installed and not the browser binary, which shrinks this module down to about 4MB. To install Puppeteer for Vercel, simply do the following:



$ npm i puppeteer-core


Enter fullscreen mode Exit fullscreen mode

Writing our Puppeteer API

Next we'll set up our API handler to generate these PDFs. By default NextJS adds a "/api" path prepended to whatever our route's name is. For this post, we'll have a "pdf.ts" route in the "pages/api" directory. We'll explain everything below but here's the code to get started:



// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
import puppeteer from 'puppeteer-core'

type Json = {
  message: string
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Json | Buffer>
) {
  const { searchParams } = new URL(
    req.url as string,
    `http://${req.headers.host}`
  )
  const url = searchParams.get('url')

  if (!url) {
    return res
      .status(400)
      .json({ message: `A ?url query-parameter is required` })
  }

  const browser = await puppeteer.connect({
    browserWSEndpoint: `wss://chrome.browserless.io?token=${process.env.BLESS_TOKEN}`,
  })

  const page = await browser.newPage()
  await page.setViewport({ width: 1920, height: 1080 })
  await page.goto(url)

  return res.status(200).send(await page.pdf())
}


Enter fullscreen mode Exit fullscreen mode

To get started we import some type information for NextJS and then import the puppeteer module from puppeteer-core. The typings aren't required if you're using plain NodeJS, so feel free to delete those in that case.

Next is a "Json" type to describe our responses back to the client. Since our handler can convert any URL into a PDF we need to make sure users supply one! Feel free to alter this block to fit your use-case or needs with puppeteer.

Finally we have our route file. This handler will check to see if there's a "?url" query-parameter for the site to convert to a PDF. If it's missing we'll return a 400 message and a response indicating that it's required. After that we simply connect to a live browser on browserless, create a page, and generate that PDF.

Making puppeteer work on Vercel with browserless

The reason we're able to get puppeteer and Chrome working on Vercel is by avoiding having to download and run Chrome inside of our Vercel app. Separating your puppeteer code from Chrome is actually a great best practice as it cleanly separates Chrome from your application code.

In order to connect to browserless and use headless Chrome you'll need to get an API token. We offer free accounts with no credit card required here. Once you have your API key, you'll want to create an env.local file with it:



# Browserless Token
BLESS_TOKEN=YOUR-API-KEY-HERE


Enter fullscreen mode Exit fullscreen mode

Now that that's set up, let's start our application and visit the route to see if it works properly. From the root of the project, run the following command. You'll want to restart this as any environment variable changes do require a restart of the dev server:



npm run dev


Enter fullscreen mode Exit fullscreen mode

Then, once it's up and ready, go to http://localhost:3000/api/pdf?url=https://www.browserless.io/docs/start. You should get a PDF file downloaded!

Deploy your Puppeteer Code on Vercel

Once we've verified everything is working properly, the next step is getting our Puppeteer + NextJS application onto Vercel. There's two ways of doing this: either the Vercel CLI or via Github. For now we'll use GitHub as a deployment method. You'll want to create a new app on Vercel by clicking "Create a New Project":

Image description

This will prompt you for a few options, but we'll want to deploy from GitHub. After adding access here's the permissions and screen grab of our GitHub selection:

Image description

Vercel should automatically recognize that this is a NextJS application, which means we won't have to inform it how to build or bundle Puppeteer, npm run build, or anything else. We will want to input our browserless token, however, as it's necessary for browserless to work:

Image description

Once in you'll click "Add" then "Deploy." After a few seconds your page should load and display their "Hello World" Screen since we never altered it:

Image description

From here you can edit the page's URL and add "/api/pdf?url=https://example.com" to it. This will verify that our Puppeteer code on Vercel works swimmingly!

Closing thoughts

With Browserless, it's easy to use a headless browser in serverless environments like Vercel. With browserless you can easily get past any file-size limits, memory limits, and have a great developer experience without the headache. Feel free to sign-up for a hosted account and get started today, or check out our example repo here.

Top comments (5)

Collapse
 
travisbeck profile image
Travis Beck

So, this solution costs minimum $200 a month? no thanks.

Collapse
 
ozgrozer profile image
Ozgur

I managed to run Puppeteer on Vercel using @sparticuz/chromium library. But it doesn't work if response time is above 15 seconds. Not sure how to deal with this but most of the time it works.

Anyone is wondering how do I do that check out the GitHub below.

Code
github.com/ozgrozer/x-image

Demo
x-image.vercel.app

Collapse
 
arslanahmed777 profile image
Arslan Ahmed Shaad

I have deployed nodejs on vercel , it deployed successfully but when i add whatsappweb js pkg in node js and also require it in the main and also copay the sample code from their website and paste it
the vercel gives me error "Serverless function crashed"
whatsappwebjs uses pupeeter under the hood and in their documentation they also give some command to add
I dont know how to add these commands on vercel
Can anyone help

Collapse
 
hajekraven profile image
Filip Hájek

Here is an alternative solution using chromium-min:
gist.github.com/hajek-raven/d05204...

Collapse
 
hehehai profile image
hehehai