How to Blur an Element in a Screenshot with CSS Selectors
Blur a specific element in a Playwright screenshot with CSS selectors. See runnable examples for screenshot assertions and direct page captures, plus masking alternatives and troubleshooting.
To blur one element in a Playwright screenshot, apply a selector-specific CSS rule at capture time. For a screenshot assertion, save the rule in a CSS file and pass its path as stylePath. For a direct page screenshot, pass the CSS text as style.
For example, this rule blurs the rendered content of the element matching .account-number:
/* screenshot.css */
.account-number {
filter: blur(8px) !important;
}
Choose a selector that matches only the intended element, then inspect the saved screenshot to confirm the result. Screenshot styling changes the captured rendering; it does not remove or alter the page’s underlying data.
1. Blur an element in a Playwright screenshot assertion
Playwright’s toHaveScreenshot() assertion accepts stylePath, which applies a stylesheet to the page for the screenshot. This is useful when a visual test needs to blur a changing value while keeping the rest of the page visible.
- Create a stylesheet such as
screenshot.cssalongside your test:
/* screenshot.css */
.account-number {
filter: blur(8px) !important;
}
- Use it in a Playwright Test assertion:
import { test, expect } from '@playwright/test';
test('account page screenshot', async ({ page }) => {
await page.goto('https://example.com/account');
await expect(page).toHaveScreenshot({
stylePath: './screenshot.css',
});
});
Replace the example URL and selector with your page and target. The selector must match the element in the rendered document when the screenshot is taken. Playwright documents screenshot stylesheets as a way to filter volatile content for visual comparisons; its example hides iframes with CSS. Playwright visual comparison documentation.
2. Blur an element in a direct page screenshot
If you call page.screenshot() directly, use the style option and supply stylesheet text. This is distinct from stylePath, which is documented for screenshot assertions.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
try {
await page.goto('https://example.com/account', {
waitUntil: 'networkidle',
});
await page.screenshot({
path: 'page.png',
fullPage: true,
style: '.account-number { filter: blur(8px) !important; }',
});
} finally {
await browser.close();
}
The Page API documents that this stylesheet pierces Shadow DOM and applies to inner frames. Playwright Page API.
Run the examples
Install Playwright and its browser if your project does not already have them:
npm install --save-dev playwright
npx playwright install chromium
For the assertion example, install the test runner package and run the test with Playwright Test:
npm install --save-dev @playwright/test
npx playwright test
Screenshot assertions are supported by the Playwright test runner. If you use another test framework, capture with page.screenshot() and compare the resulting file using your framework’s image-comparison approach. Playwright screenshot assertions.
3. Choose a selector that targets only the intended element
A CSS rule only works when its selector matches the rendered page. Prefer a stable, specific class, ID, or attribute. Avoid broad selectors such as span or .value if they also match unrelated content.
/* Class */
.account-number { filter: blur(8px) !important; }
/* ID */
#account-number { filter: blur(8px) !important; }
/* Attribute */
[data-testid="account-number"] {
filter: blur(8px) !important;
}
If the page has multiple matching elements and you only want one, refine the selector using its container or another stable attribute. For example:
.billing-panel [data-testid="account-number"] {
filter: blur(8px) !important;
}
Use browser developer tools to check that the selector matches the intended node. Then open the output image at its final display size and verify that the target is blurred and nearby content remains readable.
4. Blur or cover the element?
| Approach | What appears in the screenshot | Use it when |
|---|---|---|
CSS filter: blur(...) |
The element keeps its shape and colors, but details look softened. | You want a blurred visual treatment. |
Playwright mask |
An overlay covers the matched element’s bounding box; the default mask color is pink, and you can set another color with maskColor. |
You want a solid block over the element. |
Example mask in a screenshot assertion:
await expect(page).toHaveScreenshot({
mask: [page.locator('.account-number')],
maskColor: '#222',
});
Masking covers the matched element in the image rather than applying a blur effect. For sensitive information, do not assume a blur provides a security guarantee: inspect the exported image at full size and use a solid cover when the detail must be concealed completely. Playwright documents the mask and its color option in the PageAssertions API.
5. Version and configuration notes
stylePathfor screenshot assertions was added in Playwright v1.41.- The direct Page screenshot
styleoption was added in v1.41. maskColorwas added in v1.35.- Screenshot assertions require the Playwright test runner; use
page.screenshot()for a direct capture workflow.
If an option is rejected or missing, check the installed version rather than assuming the current documentation applies to an older project. See the Page API and PageAssertions API for option details.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The screenshot looks unchanged. | The selector does not match, the stylesheet path is wrong, or the target appears after capture. | Check the selector against the rendered DOM, confirm the path is relative to the test’s working directory, and wait for the target before capturing. |
| Several elements are blurred. | The selector matches more nodes than intended. | Scope it to a unique parent or use a more specific class, ID, or attribute selector. |
| The rule matches but the blur is too subtle. | The blur radius is too small for the element’s size or output scale. | Increase the pixel radius, capture again, and inspect the final-size image. Use a mask if the content must be fully covered. |
The assertion says stylePath is unknown. |
The installed Playwright version predates the option, or the call is not using the assertion API. | Check the installed version; stylePath was added in v1.41. For direct captures, use page.screenshot({ style: '...' }) on a compatible version. |
| The mask color option is unknown. | The installed version predates maskColor. |
Check the version; maskColor was added in v1.35. |
| Screenshot assertion APIs are unavailable in the test setup. | The project is not running Playwright Test. | Use the Playwright test runner for toHaveScreenshot(), or take a direct screenshot and compare it with the tooling already used by your test framework. |
| Blurred output still contains recognizable detail. | Blur softens pixels but does not promise secure removal of information. | Use a solid mask for sensitive values and inspect the actual exported file at full size. |
7. Performance, reliability, and cost
The CSS rule is applied as part of screenshot rendering; it does not require a separate image-editing step. The cited Playwright documentation does not provide a numeric performance benchmark for this technique, so capture time depends on the page, browser, and other work your test performs.
For repeatable visual tests, wait for the target element and any page state it depends on before capturing. Keep selectors stable, and check the produced image when changing the page or stylesheet. A missing match can leave the screenshot looking normal, while an overly broad match can blur unrelated content.
Playwright is browser automation software; this workflow does not have a per-screenshot ScreenshotNeo charge. If you want a hosted screenshot API to handle browser setup and capture, see the option below.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Its capture API returns an image or PDF from one GET request. For a capture of a page with a blur rule, pass CSS using the API’s custom CSS option; see the ScreenshotNeo API documentation for supported parameters.
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}`);
- Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers identify the page verdict and billing status.
- An MCP server lets AI agents use screenshot tools, including
take_screenshot,get_page_info, andcapture_pdf. - The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo and get 1,000 screenshots a month free, with no card.
FAQ
Can I blur an element without changing the website’s CSS?
Yes. Supply a stylesheet only for the screenshot using stylePath in an assertion or style in a direct Page screenshot.
Can I blur text inside an iframe or Shadow DOM?
Playwright documents that the direct screenshot style option pierces Shadow DOM and applies to inner frames. Confirm the selector matches the intended rendered content in your page.
Should I use a blur for redacting personal data?
Use a solid mask when information must be concealed. A blur changes appearance but is not documented as a security guarantee.


