How to capture page screenshot with Puppeteer and Express JS

Today I had to build a simple API route to capture web page screenshot. Given that I am mostly working with Node.js these days, the natural choice was to create an API route using Express.js and use Puppeteer to capture screenshot.

This API route expects three parameters; url to capture, width and height (viewport) of the page. You can use this code to create screenshots for virtually any device.


Install dependencies

npm i express puppeteer —save

Import express and puppeteer

const express = require('express')
const puppeteer = require('puppeteer')

Define route

app.get('/api/snapshot', async (req, res) => {})

Some basic checks

Either check all params or define defaults. Here I am just returning error to the client if the required params are not present

if (!req.query.url || !req.query.width || !req.query.height) {
  res.status(400).send({message: 'Invalid input'})
  return
}

Initialise Puppeteer

Now initialise puppeteer as a headless browser and open a new page

const browser = await puppeteer.launch({ headless: true })
const page = await browser.newPage()

Set viewport

Set the desired viewport as we have received via request params

await page.setViewport({ width: parseInt(req.query.width), height: parseInt(req.query.height) })

Load page

Open the url and wait until page is loaded before taking a screenshot. There are many ways to do this but the best and the most efficient seems to be a wait until ‘networkidle2‘.

networkidle2 - consider navigation to be finished when there are no more than 2 network connections for at least 500 ms.

await page.goto(req.query.url, {waitUntil: 'networkidle2'})

Take a screenshot

Now it’s time to take a screenshot, you can either defile a path or type. Use path if you want the screenshot to be created as a local file, use type to define the format with options when you want a binary buffer back.

const buffer = await page.screenshot({type: 'png'})

Send screenshot image

Thats it, we have a screenshot as a binary buffer. Now we can send this buffer back to the client.

res.setHeader('content-type', 'image/png')
res.write(buffer,'binary')
res.end(null, 'binary')

Close browser and page

await page.close()
await browser.close()

Done!


You can also find this code snippet on my github gist

Hope this post was helpful to you!

Show Comments