How to Take Screenshot with Playwright?

Screenshots are an invaluable tool when it comes to web scraping and debugging. With Playwright, taking screenshots is easy. In this comprehensive guide, we'll cover everything you need to know about taking screenshots with Playwright.

What is Playwright?

Playwright is a Node.js library for automating Chromium, Firefox, and WebKit browsers. It allows you to write tests and automation scripts that run across different browsers. Some key features of Playwright:

  • Cross-browser testing – tests run on Chromium, Firefox and WebKit out of the box
  • Automatic waiting for elements to appear before interacting
  • Network traffic interception and stubbing
  • Emulation of device sizes, locations and other conditions
  • Built-in screenshot capabilities

Playwright was created and open sourced by Microsoft and is now maintained by the Playwright community. It's a great option for anyone looking to automate or test web apps.

Why Take Screenshots with Playwright?

Here are some common use cases for taking screenshots with Playwright:

  • Visual debugging – When a test is failing, a screenshot can help pinpoint what went wrong visually. You can inspect the state of the page at the point of failure.
  • Page monitoring – Take periodic screenshots of important pages to monitor changes over time. This is useful for monitoring changes to pricing pages, detecting DOM changes that may break your scripts and more.
  • Content creation – Take screenshots to generate images for blogs, presentations and documentation.
  • Compliance – Playwright can help take screenshots in accordance with compliance requirements like financial audits.
  • Website screenshots – Take screenshots of full web pages or specific elements to use on your own site or in documentation.

Overall screenshots are invaluable for debugging, monitoring, content creation and compliance when web scraping and automating browsers with Playwright.

Taking Full Page Screenshots

Taking a full page screenshot with Playwright is straightforward. Here is an example:

const playwright = require('playwright');

(async () => {
  const browser = await playwright.chromium.launch();
  const page = await browser.newPage();
  await page.goto('http://example.com');

  // Save screenshot to disk
  await page.screenshot({path: 'example.png'});
  
  await browser.close();
})();

The key points are:

  • Launch a Playwright browser instance
  • Navigate to the page you want to screenshot
  • Call¬†page.screenshot()¬†and pass in the path to save to

This will save a screenshot of the entire visible portion of the page. Some other options you can pass to page.screenshot():

  • fullPage¬†– Scroll the full length of the page to capture the entire contents. Default is¬†false.
  • clip¬†– An object with¬†x, y, width, height¬†properties to capture only a portion of the page.
  • omitBackground¬†– Hides default white background and allows capturing PNGs with transparency.
  • encoding¬†– Encoding to use, can be either¬†binary¬†(default) or¬†base64.
  • quality¬†– The quality of the image, between 0-100. Default is 100.

For example to capture the full page, including content offscreen:

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

And to capture just a 300×300 section at 0,0:

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

This covers the basics of taking simple full page screenshots with Playwright!

Setting Viewport Size

By default, Playwright will use a viewport of 800×600. To capture screenshots at a specific viewport size you need to explicitly set it. For example to set a viewport of 1920×1080:

const browser = await playwright.chromium.launch();
const context = await browser.newContext({
  viewport: {width: 1920, height: 1080}
});

const page = await context.newPage();
await page.goto('http://example.com');
await page.screenshot({path: 'example.png'});

Setting the viewport ensures the page will be the correct dimensions for your screenshot.

Capturing Mobile Screens

To capture screenshots on mobile screens, you can use Playwright's device emulation. For example to emulate an iPhone XR:

const iPhone = playwright.devices['iPhone XR'];

const browser = await playwright.chromium.launch();
const context = await browser.newContext({
  ...iPhone,
});

const page = await context.newPage();
await page.goto('http://example.com');
await page.screenshot({path: 'iphone.png'});

Playwright has a built-in list of popular devices that can be passed on to browser.newContext() like this. You can also define a custom device with exact dimensions and user agent. This allows capturing screenshots for any mobile or desktop device.

Scrolling Element into View

By default page.screenshot() will only capture the content visible in the viewport. To capture content lower down the page, you need to scroll it into view first. For example:

const element = await page.$('.footer');
await element.scrollIntoViewIfNeeded(); 
await page.screenshot({path: 'footer.png'});

This will scroll the element into view before capturing a screenshot. You can also use page.evaluate() JavaScript to scroll to a specific Y position before taking a screenshot:

await page.evaluate(() => {
  window.scrollTo(0, 1000); 
});

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

This approach allows you to capture screenshots lower down the page after scrolling.

Screenshot of a Specific Element

In addition to full page screenshots, you can capture screenshots of specific elements on the page. For example to screenshot an element with class header:

const element = await page.$('.header');
await element.screenshot({path: 'header.png'});

This will capture a screenshot of just the element clipped to its bounding box. Some things to note about element screenshots:

  • They do not include padding or margin around the element.
  • The coordinates are relative to the page, not the viewport.
  • Transparent backgrounds are not applied like with¬†omitBackground¬†for full screenshots.

Element screenshots are useful for capturing parts of a page in isolation, like a navigation bar or sidebar.

Waiting for Elements to Load

When taking screenshots of dynamic pages, you often need to wait for elements to load before capturing. Here's how to wait until an element is visible before taking a screenshot:

const element = await page.waitForSelector('.loaded');
await page.screenshot({path: 'loaded.png'})

page.waitForSelector() will wait until the element matching the selector appears before continuing. You can also wait explicitly for network requests to settle before taking a screenshot:

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

This will wait until there are no more than 2 network connections for at least 500 ms before capturing a screenshot. Intelligent waiting ensures your screenshots fully reflect the loaded state of the page.

Setting the Screenshot File Type

By default, Playwright will save screenshots in PNG format. You can override this to use JPEG instead. For example:

await page.screenshot({path: 'image.jpeg', type: 'jpeg'});

This will save the screenshot as a JPEG file. Valid types are 'png' (default) and 'jpeg'. JPEG allows controlling compression quality with the quality option.

Handling Screenshot Failures

Sometimes browser automation moves faster than the page loads, causing a screenshot to fail. To handle failures robustly you can wrap page.screenshot() in a try/catch:

try {
  await page.screenshot({path: 'example.png'});
} catch (error) {
  console.log('Failed to capture screenshot:', error);
}

Now instead of crashing your script, a failed screenshot will log an error while allowing execution to continue.

Storing Screenshots in Memory

So far the examples have focused on saving screenshots directly to disk. But you can also capture screenshots in memory as a buffer. For example:

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

This stores the binary Buffer in memory instead of writing to disk. To then save it as a file from memory:

fs.writeFileSync('example.png', buffer);

Storing in memory can be useful for attaching screenshots to test failure reports and other cases where you don't want to write to disk directly.

Setting Output Encoding

By default screenshots are captured as binary buffers. You can also encode screenshots as Base64:

const b64 = await page.screenshot({
  encoding: 'base64'
});

The output will now be a Base64 encoded string instead of a binary buffer. Base64 encoding is useful for embedding screenshots in reports and other text-based mediums.

Adjusting Screenshot Quality

When saving screenshots as JPEGs, you can adjust the compression quality:

await page.screenshot({
  path: 'compressed.jpeg', 
  type: 'jpeg',
  quality: 50 // 0 to 100
});

Lower quality means smaller file sizes, but more compression artifacts. Quality 100 is lossless. Adjust quality to find a good balance between file size and artifacts for your use case.

Capturing Full Length Scrolls

For extremely long pages, you may want to capture the entire scroll length as a tall screenshot. Here's one way to achieve that:

// Scroll to bottom of page
await page.evaluate(() => {
  window.scrollTo(0, document.body.scrollHeight);
});

// Set clipping region taller than total scroll height
await page.screenshot({
  path: 'long.png', 
  clip: {
    x: 0,
    y: 0,
    width: 1200,
    height: 20000, 
  }
});

This scrolls fully down the page and then sets a clip region much taller than the page to capture the entire scroll. The resulting screenshot will contain the entire scrollable region vertically composited together.

Scrolling Element by Element

Another approach for long pages is scrolling element by element:

let y = 0;

while (true) {

  const clip = {x: 0, y, width: 800, height: 600};
  
  await page.screenshot({path: `part${y}.png`, clip}); 
  
  // Scroll down by clip height
  y += 600;  
  
  // Stop if we've reached end of page 
  if (y > await page.evaluate(() => document.body.scrollHeight)) {
    break;
  }

}

This incrementally takes viewport height screenshots while scrolling down the full page length. Useful for breaking up very long pages across multiple shots.

Capturing Responsive Designs

To see how a page looks across various device sizes, you can automate taking screenshots at multiple viewport widths:

const widths = [300, 600, 900, 1200];

for (const width of widths) {
  const context = await browser.newContext({
    viewport: {width, height: 800}
  });

  const page = await context.newPage();

  await page.goto('http://example.com');
  await page.screenshot({path: `${width}.png`});
  
  await context.close();
}

This loops through capturing screenshots at increasing viewport widths. The same approach can be used to screenshot multiple mobile devices, etc. Very useful for evaluating responsive designs.

Handling Popups and New Tabs

By default, Playwright will only capture screenshots of the page that's currently focused. To capture other open popups or tabs, you first need to switch focus to them:

const [page1, page2] = await browser.pages();

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

Now the screenshot will contain page2 instead of page1 which would be the default focused tab. This allows you to orchestrate screenshots across multiple opened tabs and windows.

Waiting for Navigation

When navigating between pages, you'll want to wait for the navigation to finish before taking a screenshot:

await page.click('a.next-page'); 
await page.waitForNavigation();
await page.screenshot({path: 'next-page.png'});

page.waitForNavigation() pauses execution until the new page finishes loading before continuing. This ensures you capture the next page in its loaded state.

Scoping Browser Contexts

By default, Playwright screenshots capture the entire browser viewport. To isolate screenshots, use browser contexts:

const context = await browser.newContext();
const page = await context.newPage();

await page.goto('http://example.com');
await page.screenshot({path: 'example.png'});

Now screenshots will only contain the context page, allowing you to scope particular workflows. Closing the context after capturing ensures no crosstalk across contexts.

Handling Multi-Page Apps

For complex single page apps, you may need to interact with the page dynamically before capture:

// Login user
await page.click('#login');
await page.type('#username', 'test');

// Wait for dashboard elements to appear
await page.waitForSelector('.dashboard');

// Capture loaded state
await page.screenshot({path: 'dashboard.png'});

Using Playwright to log users in or trigger loaded states allows you to screenshot deeper into the app after dynamic content loads.

Setting Background Color

By default, screenshots have a white background. You can set the background to match your page by using CSS:

await page.evaluate(() => {
  document.body.style.backgroundColor = 'rebeccapurple'; 
});

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

Now the screenshot will use the matched background rather than white. This ensures a seamless blend between the content and background.

Redacting Sensitive Information

When capturing screenshots containing sensitive information, you may need to redact parts of the image. One approach is using the clip option and taking multiple screenshots:

// Login area
await page.screenshot({
  path: 'redacted-top.png',
  clip: {x: 0, y: 0, width: 300, height: 300}
});

// Main content
await page.screenshot({
  path: 'redacted-bottom.png', 
  clip: {x: 0, y: 300, width: 300, height: 4000} 
});

Now you have separate top and bottom screenshots without the sensitive middle section.

Embedding Screenshots in Reports

To embed screenshots directly into test reports and other output:

const buffer = await page.screenshot();

console.log(`
<div>
  <h2>Screenshot</h2>
  <img src="data:image/png;base64,${buffer.toString('base64')}" />  
</div>
`);

This captures the screenshot buffer, and encodes it as Base64 directly in the output. Handy for integrating screenshots into HTML, PDF, and CLI reports.

Troubleshooting Headless Captures

If your headless screenshots aren't capturing the page correctly:

  • Use¬†--window-size¬†when launching to explicitly set browser size
  • Wait for network and DOM readiness before capturing
  • Interact with the page to trigger dynamic content and loaded state
  • Set timeout and retry screenshots in case of failures
  • Launch without a headless flag to see what browser is rendering

Debugging visibly helps identify discrepancies versus the headless browser.

Conclusion

With Playwright's versatile screenshot capabilities, you can capture exactly what you need from full pages down to individual elements on desktop and mobile. Integrate screenshots into your scraping and testing workflows for invaluable visual feedback and debugging.

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