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 isfalse
.clip
– An object withx, 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 eitherbinary
(default) orbase64
.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.