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!