This guide shows you how to use Playwright’s screenshot capabilities to verify that your web pages render correctly across different screen sizes. You’ll learn to capture full-page and element-specific screenshots at various viewport widths, compare them against baseline images, and automate the entire process so layout regressions are caught before they reach production.
What You’ll Need
- Node.js (version 16 or later) installed on your machine
- A basic understanding of JavaScript and command line usage
- A Playwright project set up (either via
npm init playwrightor manually installing@playwright/test) - Access to the web page you want to test (local or remote URL)
Step-by-Step
- Install Playwright Test – If you haven’t already, run
npm init playwright@latestin your project directory. This sets up the test runner and installs browsers. For an existing project, runnpm install -D @playwright/testand thennpx playwright installto download the browser binaries. - Create a test file – In your
testsfolder, create a new file, e.g.,responsive.spec.js. This will contain all your screenshot tests. - Import test and expect – At the top of the file, add:
const { test, expect } = require('@playwright/test');(or use ES modules if your project is configured that way). - Define viewport sizes – Create an array of common screen sizes you want to test. For example:
const viewports = [ { width: 375, height: 667 }, { width: 768, height: 1024 }, { width: 1920, height: 1080 } ];These represent mobile, tablet, and desktop. - Write a loop for each viewport – Use
for (const viewport of viewports) { test(`Screenshot at ${viewport.width}px`, async ({ page }) => { ... }); }This generates a separate test for each screen size. - Set the viewport size – Inside the test, call
await page.setViewportSize(viewport);before navigating to the page. This ensures the browser window matches the desired dimensions. - Navigate to your page – Use
await page.goto('https://example.com');(replace with your actual URL). Wait for the page to load fully, usingawait page.waitForLoadState('networkidle');if necessary. - Take a full-page screenshot – Use
await page.screenshot({ path: `screenshots/${viewport.width}.png`, fullPage: true });This captures the entire scrollable area of the page, not just the visible viewport. - Take an element screenshot (optional) – To capture a specific component, first locate it:
const header = await page.locator('header');thenawait header.screenshot({ path: `screenshots/header-${viewport.width}.png` });This is useful for checking a navigation bar or hero section in isolation. - Run the tests – Execute
npx playwright testfrom your terminal. Playwright will run each test and save the screenshots to the specified paths. - Set up visual comparison (baseline) – To automatically detect changes, use Playwright’s built-in
expect(page).toHaveScreenshot(). First run will create a baseline image. Subsequent runs compare against it and fail if the screenshot differs by more than a threshold. - Update baselines when intended – When you intentionally change the UI, run
npx playwright test --update-snapshotsto overwrite the stored baseline images with the new ones.
Common Mistakes
- Not waiting for fonts or images – Screenshots taken before web fonts load or images finish rendering will show unstyled text or blank areas. Always wait for network idle or use
page.waitForSelectorfor critical elements. - Ignoring scroll behavior – A full-page screenshot captures the entire page, but if your page has sticky headers or lazy-loaded content, the screenshot may not reflect what a user actually sees at a given scroll position. Consider taking viewport-only screenshots for those cases.
- Using fixed paths without cleanup – If you reuse the same screenshot path, old images are overwritten. That’s fine, but if you delete a test, the old screenshot remains. Clean up your screenshots folder regularly.
- Comparing screenshots across different environments – Font rendering, OS-level anti-aliasing, and GPU differences can cause false positives. Run visual comparisons on the same operating system and browser version to keep results consistent.
Tips
- Use a dedicated screenshot directory – Create a
screenshots/folder and add it to your.gitignoreif you don’t want baseline images in version control. For baselines, keep them in a separate folder likescreenshots/baselines/and commit them. - Set a global viewport in config – You can define default viewport sizes in
playwright.config.jsunderuse: { viewport: { width: 1280, height: 720 } }, but for responsive tests you’ll override per test. - Use device emulation for mobile – Playwright has built-in device descriptors like
devices['iPhone 12']that set viewport, user agent, and touch support. Usetest.use({ ...devices['iPhone 12'] })for realistic mobile testing. - Mask dynamic content – If your page has timestamps, ads, or random elements, use
page.screenshot({ mask: [locator] })to cover them with a colored box before capturing, preventing false mismatches.
Troubleshooting
- Screenshots are blank or incomplete – This usually means the page hasn’t finished loading. Increase wait times or use
await page.waitForLoadState('networkidle'). If lazy-loaded images are below the fold, scroll to them first or usefullPage: trueafter scrolling. - Visual comparison fails even though nothing changed – Check for anti-aliasing differences, animations, or dynamic content. Try setting
animations: 'disabled'in the test options or usepage.emulateMedia({ reducedMotion: 'reduce' }). Also, set amaxDiffPixelRatiointoHaveScreenshotto allow tiny differences. - Tests fail on CI but pass locally – CI environments often have different font rendering. Install system fonts, use a headless browser with the same version, and ensure your CI machine has the same operating system as your local machine.
- Cannot find the element for element screenshot – Use a more specific selector. If the element is inside a shadow DOM, use
page.locator('selector', { has: page.locator('...') })or pierce the shadow root withpage.locator('css=...').
Frequently Asked Questions
How do I take a screenshot of only the visible viewport?
Simply omit the fullPage option or set it to false. The default is false, so page.screenshot({ path: 'viewport.png' }) captures only the current viewport.
Can I test multiple pages in one test?
Yes, you can navigate to multiple URLs within a single test and take screenshots of each. However, for better isolation and clearer failure messages, it’s recommended to use separate tests for each page.
How do I set a custom pixel ratio for high-DPI screens?
Use page.setViewportSize({ width, height }) and also set deviceScaleFactor via page.context().newPage() with options. For example: const context = await browser.newContext({ viewport: { width: 375, height: 667 }, deviceScaleFactor: 2 });
What is the best way to store baseline screenshots?
Keep them in a separate directory like __screenshots__ and commit them to your repository. This allows team members to see what the expected UI looks like and makes it easier to review changes.
Can I use Playwright screenshots for non-UI testing, like PDF generation?
Yes, you can use page.pdf() for headless Chromium to generate PDFs of the page, which is useful for reports or documentation. This is separate from screenshot functionality but works similarly.
How do I ignore a specific area when comparing screenshots?
Use the mask option in toHaveScreenshot or page.screenshot. Pass an array of locators that point to the areas you want to mask. Playwright will cover them with a solid color before capturing.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Poco C51 Airtel Prepaid Locked Variant India?
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Campus Tech Innovation Hubs: What They Are
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It