How to Take a Screenshot with Puppeteer?

If you want to capture screenshots of web pages programmatically, Puppeteer is one of the most popular and powerful tools for the job. In this comprehensive guide, we'll cover everything you need to know about using Puppeteer to take screenshots in your Node.js applications.

Whether you're looking to automate screenshotting for testing, web scraping, debugging, or any other use case, this guide has you covered. Let's dive in!

Why Take Screenshots with Puppeteer?

Before we dive into the methods and syntax, let's discuss why you might want to take screenshots programmatically in the first place. Here are some of the main use cases for taking screenshots with Puppeteer:

Debugging and Testing Websites

One of the most common uses for Puppeteer screenshots is debugging and testing websites during development. Screenshots allow developers to:

  • Identify layout issues and CSS bugs that may only occur on certain platforms or viewport sizes.
  • Compare before and after screenshots when refactoring code to detect visual regressions.
  • Document test scenarios and steps with accompanying screenshots.
  • Capture screenshots to illustrate bug reports.
  • Test on multiple devices by setting different viewport sizes.

Web Scraping and Archiving

For web scraping tasks, it can be useful to save copies of pages being scraped:

  • Archive versions of website pages over time for monitoring changes.
  • Document the data collection process with accompanying screenshots.
  • Create datasets by extracting screenshots of products/articles being scraped.

Monitoring and Automated Checks

You can build automated screenshot-based monitoring for sites:

  • Programmatically check for visual differences in sites by comparing screenshots daily/weekly.
  • Detect when a site layout breaks by comparing it against a known good screenshot.
  • Monitor uptime by checking that a screenshot can be successfully captured.

Documentation and Reporting

Some other documentation use cases include:

  • Creating screenshots for tutorials, presentations, documentation etc.
  • Programmatically generating screenshots to document an internal app for stakeholders.
  • Building visual reports and summaries by stitching screenshots together.

Automated Testing

For automated browser testing, screenshots are useful for:

  • Validating UI functionality and layout by comparing against known good screenshots.
  • Catching visual regressions and cross-browser differences.
  • Documenting and reporting on automated test runs.

So, in summary, whenever you need to generate screenshots of web pages in Node programmatically, Puppeteer is up to the job!

Step-by-Step to Take a Screenshot with Puppeteer

To take a screenshot with Puppeteer, you need to follow these steps:

1. Create a Browser Instance and a New Page: First, create a Chrome browser instance in headless mode. Then, create a new page in the browser.

const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
const page = await browser.newPage();

2. Navigate to a URL: Open the URL of the webpage you want to capture in the current page.

const website_url = 'https://www.example.com';
await page.goto(website_url, { waitUntil: 'networkidle0' });

3. Capture a Screenshot: Use the page.screenshot() method to capture the screenshot. You can specify the path where you want to save the screenshot.

await page.screenshot({ path: 'screenshot.jpg' });

4. Close the Browser: Finally, close the browser instance after the screenshot is completed.

await browser.close();

This is the complete code for the operation:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  const website_url = 'https://www.example.com';
  await page.goto(website_url, { waitUntil: 'networkidle0' });
  await page.screenshot({ path: 'screenshot.jpg' });
  await browser.close();
})();

To take a full-page screenshot, add fullPage: true to page.screenshot():

await page.screenshot({ path: 'screenshot_full.jpg', fullPage: true });

This will take a full-page screenshot of the web page instead of capturing just a part of the web page that fits the viewport. You can also capture multiple screenshots of different web pages by passing in the URLs as an array and saving them in a folder.

To take a screenshot of a particular HTML element, you can use the element.screenshot() method. You need to select the element using its selector, which you can get by inspecting the element on the webpage.

const element = await page.$('element_selector');
await element.screenshot({ path: 'element_screenshot.jpg' });

Remember to replace 'element_selector' it with the actual selector of the HTML element you want to capture.

Basic Screenshot Syntax in Puppeteer

The core syntax for taking screenshots with Puppeteer is simple. You use the screenshot() method on either:

  • Page object – To capture a screenshot of the entire page frame.
  • An ElementHandle object – To capture a specific DOM element on the page.

Here is a basic example of capturing the full page:

// Load page
const page = await browser.newPage();
await page.goto('https://example.com');

// Screenshot of full page 
await page.screenshot({path: 'page.png'});

And taking a screenshot of a specific element:

// Get DOM element
const navbar = await page.$('#main-nav'); 

// Screenshot of element
await navbar.screenshot({path: 'navbar.png'});

The screenshot() method accepts an object containing options:

screenshotOptions = {

  // Required - The file path to save the image to 
  path: 'screenshot.png',

  // Optional - The image format, can be either jpeg | png | webp
  type: 'png',

  // Optional - Quality level 0-100 (for jpeg images)
  quality: 100,

  // Optional - Full page screenshot, enabled by default on page screenshots
  fullPage: true 

}

Let's explore some common examples in more detail…

Capturing Full Page Screenshots

To capture the entire height of a page, you enable the fullPage option:

await page.goto('https://example.com');

await page.screenshot({
  path: 'page.png',
  fullPage: true // Enable full height screenshot
});

This will automatically scroll the page and stitch together a screenshot of the entire scrollable region.

Tip: Always wait for the load event before screenshotting to ensure the page has fully rendered:

await page.goto('https://example.com', {waitUntil: 'load'});

You can also set an exact viewport size before capturing a screenshot:

// Set viewport to 1024 x 768
await page.setViewport({width: 1024, height: 768})

await page.screenshot({path: 'page.png'});

This results in a predictable screenshot size, useful for things like responsive testing.

Element Screenshots

To capture a single DOM element, first get a handle to it using page.$():

const logo = await page.$('#logo');

Then pass the element handle to screenshot():

await logo.screenshot({path: 'logo.png'});

This will create a cropped screenshot of just that element.

Advanced Puppeteer Screenshot Techniques

In addition to basic full-page and element screenshots, Puppeteer provides some advanced capabilities.

Specifying Clip Regions

You can take a screenshot of a specific clip region of the page using the clip option:

await page.screenshot({
  path: 'region.png',
  clip: {
    x: 0,
    y: 0,
    width: 500,
    height: 500
  }
});

This allows capturing arbitrary regions, useful for things like small diffs.

Tall Multi-Page Screenshots

To capture tall pages that require scrolling, you can stitch together a series of full page screenshots:

const pageHeight = await page.evaluate('document.body.scrollHeight');

// Screenshot each portion of page
await page.screenshot({path: 'top.png', fullPage: true}); 

await page.evaluate('window.scrollTo(0, 500)');
await page.screenshot({path: 'middle.png', fullPage: true});

await page.evaluate('window.scrollTo(0, 1500)'); 
await page.screenshot({path: 'bottom.png', fullPage: true}); 

// Combine images into final result

Lazy Loaded Content

Some sites load content lazily on scroll. To capture this, manually scroll before screenshotting:

await page.goto('https://example.com');

// Scroll down to trigger lazy loading
await page.evaluate('window.scrollBy(0, 1000)'); 

// Wait for lazy content to load
await page.waitForSelector('.lazy-item');

// Screenshot loaded content
await page.screenshot({path: 'lazy.png'});

Animations and Transitions

To screenshot at specific points during CSS animations and transitions, use page.waitForFunction():

// Start animation
await page.evaluate(() => {
  document.querySelector('.animating-element').classList.add('start'); 
});

// Wait for animation mid-point
await page.waitForFunction(() => {
  // Checks for animation 50% complete
});

// Screenshot mid-way through animation
await page.screenshot({path: 'animating.png'});

This allows you to coordinate screenshots at precise animation states.

Limitations to Note

Some limitations to be aware of when using Puppeteer's screenshotting capabilities:

  • The resulting image will only include content visible in the browser viewport. Any clipped or hidden content will not be captured.
  • For very complex web apps, some content and functionality may not execute in a headless browser, so screenshots may omit some dynamic content.
  • There are no native options for capturing full web page PDFs, scrolling timelines, or multiplayer screen areas. You would need additional libraries to stitch together more advanced screenshot combinations.
  • There can be inconsistencies with mobile viewports and touch events compared to real mobile devices. Use emulation with caution.
  • For captcha and bot detection systems, headless browsers can sometimes be detected and blocked.

Real-World Puppeteer Screenshot Examples

To demonstrate some real-world uses of browser screenshot automation, here are a few examples:

Visual Regression Testing

Compare before and after screenshots to detect unintended changes to UI:

// 1. Baseline screenshot
const before = await page.screenshot(); 

// 2. Make code changes

// 3. Screenshot after changes  
const after = await page.screenshot();

// 4. Use pixel match library to compare
const diff = await checkScreenshotDiff(before, after);

if (diff.percentage > 1) {
  console.error('Visual change detected!');
} else {
  console.log('No visual changes found.');
}

Scraping Product Images

Loop through products on a page, saving each product image:

// Get product elements
const products = await page.$$('.product');

for (const product of products) {
  
  const image = await product.$('img');

  const productId = await product.evaluate(el => el.id);

  await image.screenshot({path: `product-${productId}.png`}); 

}

Monitoring Page Changes

Take periodic screenshots of a page to track differences over time:

// Initial base screenshot
await page.goto('https://news.ycombinator.com/');
let base = await page.screenshot();

// Check for changes every hour
setInterval(async() => {

  await page.goto('https://news.ycombinator.com/');

  const current = await page.screenshot();

  const diff = await checkScreenshotDiff(base, current);

  if (diff.percentage > 10) {
    console.log('Significant change detected!');
    base = current; // Update base
  }

}, 3600000); // 1 hour

This allows detecting when the page layout significantly changes. As you can see, when combined with other libraries, screenshot automation enables all kinds of useful applications!

Debugging Common Puppeteer Screenshot Issues

While screenshots are generally straightforward in Puppeteer, here are some common issues and how to resolve them:

  • Blank screenshots: This is typically caused by taking screenshots before a page has fully loaded. Always wait for load event before capturing:
await page.goto(url, {waitUntil: 'load'});
  • Elements clipped or missing: By default, screenshots only capture the viewport region. Use full-page screenshots or scroll elements into view first.
  • Low-quality images: JPEGs default to 80% quality. Increase the quality option if needed. PNGs will have lossless quality.
  • Big file sizes: Use JPEG for smaller files or WebP, which has superior compression.
  • Timeout errors: Slow pages may need increased timeouts. Set the timeout option when launching Puppeteer.
  • Headless not supported: A small number of sites try to block headless browsers. Use puppeteer. launch({headless: false}) to disable headless mode.
  • Blocked by Bot Protection: Rotate IPs with residential proxies like Bright Data, Smartproxy, Proxy-Seller, and Soax and add human-like behaviors (mouse movements, variable delays) to avoid bot detection.
  • Distorted mobile screenshots: Explicitly set mobile viewport dimensions for accurate, responsive screenshots.

In general, allow time for pages to load, use reasonable timeouts, and ensure elements are in view for clean, accurate screenshots.

Generating PDFs from Screenshots

In addition to images, you can stitch screenshots together into PDF reports using libraries like Puppeteer-to-PDF:

// PDF creation helpers 
const {createPdf} from 'puppeteer-to-pdf';

// Screenshot each page section
const page1 = await page.screenshot({fullPage: true}); 
await page.click('#page-2');
const page2 = await page.screenshot({fullPage: true});

// Create single PDF 
const pdf = await createPdf([
  {url: page1}, // Page 1  
  {url: page2} // Page 2
]);

await pdf.saveAs('report.pdf'); // Save combined PDF

This allows programmatically generating PDF versions of sites and pages from screenshots.

Extracting Text from Screenshots with OCR

You can also run Optical Character Recognition (OCR) on screenshots to extract text:

// Take screenshot
const screenshot = await page.screenshot(); 

// Run OCR with Tesseract.js
const {data: {text}} = await worker.recognize(screenshot); 

console.log(text); // Print extracted text

Helpful for capturing text from dynamic content that can't be directly copied.

Best Practices for Puppeteer Screenshots

Here are some top tips for taking production-grade screenshots with Puppeteer:

  • Wait for pages to fully load before capturing to ensure complete content.
  • Set explicit viewport dimensions for appropriate mobile or desktop sizes.
  • Scroll tall pages and allow time for lazy loaded content.
  • Use full page mode for entire page scroll height.
  • Capture specific elements when possible vs full screenshots.
  • Use reasonable timeouts for complex pages and actions.
  • Enable mobile emulation to test responsive designs.
  • Detect animations finishing before taking screenshots.
  • Set JPEG quality to 100 for lossless images.
  • Limit screenshot frequency to avoid detection by sites.
  • Combine with proxies to distribute requests across many IPs.

Conclusion

Automated screenshot generation is useful for so many digital automation tasks. Puppeteer provides a powerful API for controlling headless Chrome and capturing predictable, production-ready screenshots.

Hopefully, this guide has provided you a comprehensive overview of taking screenshots with Puppeteer! The ability to programmatically capture screenshots is an invaluable tool for web scraping, testing, monitoring, debugging, and automation.

John Rooney

John Rooney

John Watson Rooney, a self-taught Python developer and content creator with a focus on web scraping, APIs, and automation. I love sharing my knowledge and expertise through my YouTube channel, My channel caters to all levels of developers, from beginners looking to get started in web scraping to experienced programmers seeking to advance their skills with modern techniques. I have worked in the e-commerce sector for many years, gaining extensive real-world experience in data handling, API integrations, and project management. I am passionate about teaching others and simplifying complex concepts to make them more accessible to a wider audience. In addition to my YouTube channel, I also maintain a personal website where I share my coding projects and other related content.

We will be happy to hear your thoughts

      Leave a reply

      Proxy-Zone
      Compare items
      • Total (0)
      Compare
      0