Vercel + Puppeteer
Tags: puppeteer, vercel, nextjs, browserless
Published: 2023-04-17 17:28:09


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](https://github.com/browserless/vercel-puppeteer).

## Best practices and setting up
- We're using [Next.JS](https://github.com/vercel/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](https://nextjs.org/docs/basic-features/environment-variables).
- 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:

```sh
$ npx create-next-app@latest
```

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:

```sh
$ npm i puppeteer-core
```

## 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:

```ts
// 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())
}
```

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](https://www.browserless.io/sign-up-cloud-unit/). Once you have your API key, you'll want to create an env.local file with it:

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

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:

```sh
npm run dev
```

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](https://vercel.com/docs/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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bycyk19fltzz0ez7kf7v.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y84uval3x3t0tzonv552.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct023i6zj4qb6awpdb37.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jphctxfke92fc7i40mwz.png)

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](https://www.browserless.io/sign-up/) and get started today, or check out our [example repo here](https://github.com/browserless/vercel-puppeteer).