DEV Community

Alex Araiza
Alex Araiza

Posted on

Take better screenshots with Puppeteer

Images are an important part of every website. They help convey meaning and emotion, and they can make any design more attractive—or less, depending on how you use them. So whether it's photographs, illustrations or renders, getting good images is an important step in web development.

Using screenshots is a common practice, especially for web developers showcasing their work in a portfolio; but the most popular screen capturing tools don't allow for much customization, so the quality of the resulting images may not be good enough. Thankfully, there are other tools; like Puppeteer, which does allow for plenty of customization.

What is Puppeteer?

Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium.

When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API.

You can automate many tasks with Puppeteer, one of them being taking screenshots.

Getting started

To get started, you need to install Puppeteer:

npm install puppeteer
Enter fullscreen mode Exit fullscreen mode

or

yarn add puppeteer
Enter fullscreen mode Exit fullscreen mode

Then, create a file with the following code:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://www.w3schools.com/howto/tryhow_css_example_website.htm');
  await page.screenshot({ path: 'example.png' });
  await browser.close();
})();
Enter fullscreen mode Exit fullscreen mode

The code above takes a screenshot of https://www.w3schools.com/howto/tryhow_css_example_website.htm and saves it to example.png.

example.png

Resolution

Screenshots are 800x600px by default, but you can change their resolution:

await page.setViewport({
  width: 640,
  height: 480,
  deviceScaleFactor: 1
});
Enter fullscreen mode Exit fullscreen mode

example.png

setViewport resizes the page, so if the page you want to screenshot doesn't handle viewport resizing well, you may want to call this method before calling goto.

Changing deviceScaleFactor lets you get an image with a different resolution without changing the size of the viewport. This can be useful when you want a high-resolution image with a page layout that is specific to a certain viewport size.

Waiting for elements to load

It's possible that some elements aren't fully loaded when the screenshot is taken. You can make your script wait for them to load using two different methods:

await page.waitForSelector('img');
Enter fullscreen mode Exit fullscreen mode
await page.waitForXPath('//img');
Enter fullscreen mode Exit fullscreen mode

Both methods will return as soon as the specified selector or XPath exists, so they will only wait for the first element with the specified selector or XPath to load.

Waiting some more

You can also make your script wait for a number of milliseconds:

await page.waitForTimeout(1000);
Enter fullscreen mode Exit fullscreen mode

This can be useful to make your script wait for an animation to finish before taking a screenshot (or to make your script wait for elements to load if you're feeling lazy and don't want to get the selector or XPath of the elements).

It's generally recommended to not wait for a number of seconds, but instead use Page.waitForSelector(), Page.waitForXPath() or Page.waitForFunction() to wait for exactly the conditions you want.

Full page screenshot

You can take screenshots of the full scrollable page by setting fullPage to true:

await page.screenshot({ path: 'example.png', fullPage: true });
Enter fullscreen mode Exit fullscreen mode

Specific area of the page

You can take screenshots of a specific area of the page by setting clip to an object with the x and y coordinates of the top-left corner of the area, and the width and height of the area:

await page.screenshot({
  clip: {
    x: 50,
    y: 100,
    width: 150,
    height: 100
  },
});
Enter fullscreen mode Exit fullscreen mode

Transparency

You can take screenshots without the default white background by setting omitBackground to true:

await page.screenshot({ path: 'example.png', omitBackground: true });
Enter fullscreen mode Exit fullscreen mode

Keep in mind that this only applies to the default background, so if the background of any element is not transparent, it will show on the screenshot. Not to worry, you can set the background of any element to be transparent by running JavaScript in the page's context.

Running JavaScript

You can run a JavaScript function in the page's context:

await page.evaluate(() => {
  let element = document.getElementById('elementWithBackground');
  element.style.background = 'transparent';
  document.body.style.background = 'transparent';
});
Enter fullscreen mode Exit fullscreen mode

The code above sets the background of the element with ID 'elementWithBackground' and the body to be transparent, but you can modify the page in any way so you can get the exact screenshot you need.

Mind the size

Part of making the user experience great is making sure that the end user can see the images, and that isn't going to happen if they're using a 3G phone while trying to download a 42MB image. Make sure the images you send to the end user are an appropriate size!

Conclusion

This post should help you get most of the screenshots you need, but you can always take a look at the Puppeteer documentation to learn more.

Here's some code with most of the methods mentioned in this post:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.setViewport({
    width: 640,
    height: 480,
    deviceScaleFactor: 1
  });
  await page.goto('https://www.w3schools.com/howto/tryhow_css_example_website.htm');
  await page.waitForSelector('img');
  await page.waitForTimeout(1000);
  await page.evaluate(() => {
    let element = document.getElementById('elementWithBackground');
    element.style.background = 'transparent';
    document.body.style.background = 'transparent';
  });
  await page.screenshot({ path: 'example.png', fullPage: true, omitBackground: true });
  await browser.close();
})();
Enter fullscreen mode Exit fullscreen mode

Feel free to modify this however you want. Have fun with it!

Discussion (0)