ScreenshotNeo

BlogHow-to

How to Mask Dynamic User Avatars in Playwright Visual Tests

Mask changing avatars with Playwright locator-based screenshot assertions, or hide them with screenshot CSS when an overlay should not appear in the baseline.

By the ScreenshotNeo team4 October 20265 min read

Use Playwright Test’s toHaveScreenshot() assertion with its mask option. Pass a locator that matches only the avatars whose pixels change between runs. Playwright covers each matched element’s bounding box with an overlay; the default is pink (#FF00FF), and maskColor lets you choose another color. [Playwright visual comparisons] [Playwright Page API]

1. Set up a visual screenshot assertion

This example uses TypeScript and Playwright Test. It assumes the application exposes a stable test ID for avatar elements; replace user-avatar with a selector from your own markup. No universal avatar selector exists.

import { test, expect } from '@playwright/test';

test('profile page matches its visual baseline', async ({ page }) => {
  await page.goto('/profile');

  await expect(page).toHaveScreenshot('profile.png');
});

On the first run, Playwright creates a baseline screenshot. Later runs compare against it. Review baseline changes deliberately and keep the baseline files under version control. [Visual comparisons]

2. Mask dynamic avatars with locators

Pass a locator in the assertion’s mask array. A test ID is usually a robust choice when your application can provide one.

import { test, expect } from '@playwright/test';

test('profile page ignores changing avatar pixels', async ({ page }) => {
  await page.goto('/profile');

  await expect(page).toHaveScreenshot('profile.png', {
    mask: [page.getByTestId('user-avatar')],
  });
});

For multiple avatars, use a locator that matches every intended avatar. Check its scope so it does not also mask stable imagery you want the test to compare. Playwright masks the bounding boxes of matched elements, including invisible elements, so an overly broad locator can hide more than expected. [Page API: screenshot options]

Choose a locator grounded in your markup

Examples below show possible application markup, not built-in Playwright selectors. Use whichever stable hook your app provides.

// Markup: <img data-testid="user-avatar" ...>
const avatar = page.getByTestId('user-avatar');

// Or, if the app has an accessible label:
const avatarByLabel = page.getByRole('img', { name: 'User avatar' });

// Or use an application-specific CSS selector:
const avatarByCss = page.locator('[data-visual-test="avatar"]');

await expect(page).toHaveScreenshot({ mask: [avatar] });

Prefer a dedicated test ID or another selector that identifies only the intended avatars. Avoid copying a made-up class name without checking the application’s DOM.

Change the overlay color

maskColor customizes the overlay. Playwright documents the default as #FF00FF; the option was added in Playwright v1.35.

await expect(page).toHaveScreenshot('profile.png', {
  mask: [page.getByTestId('user-avatar')],
  maskColor: '#888888',
});

3. Decide whether to mask or hide avatars

Masking preserves the element’s bounding-box footprint in the screenshot and replaces its pixels with a solid overlay. Use it when layout should remain visible but avatar appearance is volatile. If the baseline should show no avatar content or overlay, use screenshot styles to hide or filter the region instead. Playwright’s visual-comparison guide describes stylePath as a way to filter dynamic or volatile elements; the PageAssertions API marks this option as available since v1.41. [Visual comparisons] [PageAssertions API]

// tests/visual.css
test-avatar, [data-testid="user-avatar"] {
  visibility: hidden !important;
}
await expect(page).toHaveScreenshot('profile.png', {
  stylePath: './tests/visual.css',
});

Use selectors that match your actual markup. Screenshot styles are useful for broader visual cleanup; locator masks are more explicit when you want a particular set of elements covered.

4. Keep the rest of the screenshot deterministic

Masking only removes avatar appearance from the visual comparison. It does not check whether the right avatar URL loaded or whether avatar behavior works. If those behaviors matter, assert them separately.

Keep baseline creation and comparison in a consistent environment where practical. Playwright notes that host operating system, browser version, settings, hardware, power source, and headless mode can affect rendering. A masked avatar will not eliminate differences elsewhere on the page. [Visual comparisons]

5. Troubleshoot common problems

Symptom Likely cause Fix
The avatar still changes the screenshot The locator does not match the rendered avatar, or the screenshot assertion runs before the relevant page state is present. Inspect the app’s markup, use a locator that matches the avatar, and make sure the page has reached the state you intend to capture.
Too much of the page is covered The locator matches extra elements, or a broad selector includes non-avatar imagery. Scope the locator to the avatar region or use a dedicated test ID. Remember that invisible matched elements are masked too.
The mask color option is rejected The installed Playwright version predates maskColor. Check the project’s installed version; maskColor is documented since v1.35. Upgrade if appropriate, or omit the option and use the default color.
stylePath is unknown The installed Playwright version predates support for this option. Check the installed version. The PageAssertions API marks stylePath as available since v1.41, or use locator masking instead.
The screenshot still fails after masking Other pixels differ, such as fonts, layout, images, or browser rendering. Compare in a consistent environment and inspect the diff. Mask only the known volatile region so real regressions elsewhere remain detectable.

6. Performance, reliability, and maintenance

Masking is a screenshot assertion option, so it avoids the need to alter application behavior just to make avatar pixels stable. Its reliability depends on keeping the locator aligned with the rendered DOM and controlling the screenshot environment. If the markup changes, update the locator and review the visual baseline as part of the change.

Use masking for volatile pixels rather than as a way to make every screenshot pass. Overly broad masks reduce what the visual assertion can detect. Pair the screenshot with separate checks for avatar loading or selection when those are requirements.

Or skip the browser setup

If you need screenshots outside a Playwright test, ScreenshotNeo is a website screenshot API and MCP server. Its one-call API returns an image or PDF, and its screenshot options include CSS selectors, custom CSS and JavaScript, waiting, and device settings. See the ScreenshotNeo API docs.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, and failed loads are never billed, and the response identifies the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

FAQ

Does masking validate that the avatar loaded correctly?

No. It removes avatar appearance from visual comparison. Add a separate assertion if loading or avatar selection is part of the behavior under test.

Can I choose the mask color?

Yes. Set maskColor; the default overlay is #FF00FF. The option is documented since Playwright v1.35.

When should I use screenshot styles instead?

Use stylePath when hiding or filtering volatile content is preferable to showing an overlay. It is documented as available since Playwright v1.41.