How to hide an element in a Playwright screenshot without changing the page
Use Playwright’s capture-time CSS to hide an element in a screenshot without changing the page. Learn when to use visibility, display, or screenshot assertions.
Use Playwright’s screenshot-time style option to apply CSS only while a screenshot is captured. For example, visibility: hidden makes an element invisible while preserving its layout space; use display: none when the captured layout should close the gap. Neither rule needs to be added permanently to your page.
Hide an element in a regular Playwright screenshot
The style option is available on page.screenshot() starting with Playwright v1.41. Pass a CSS string that targets the element you want hidden:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
try {
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.screenshot({
path: 'screenshot.png',
style: '.cookie-banner { visibility: hidden !important; }',
fullPage: true,
});
} finally {
await browser.close();
}
})();
Install Playwright with npm install playwright and install its browser with npx playwright install chromium. Replace .cookie-banner with a selector that uniquely matches the element on your page. The capture stylesheet is applied for the screenshot; it does not become a lasting application style.
Choose whether to preserve the layout
| CSS rule | What the screenshot shows | Use it when |
|---|---|---|
visibility: hidden |
The element is invisible, but its space remains. | Nearby content should stay in the same position. |
display: none |
The element and its layout space are removed. | Content should move into the space left behind. |
opacity: 0 |
The element is transparent, but still occupies space and may still affect interactions or overlays. | Use only when transparency is specifically what you want. |
For example, change the rule to .cookie-banner { display: none !important; } to remove the banner’s space in the captured layout. The !important declaration helps the capture rule take precedence over ordinary page styles.
Target the right element
Inspect the page to identify a stable selector, such as a unique class, ID, or attribute. Avoid broad selectors like div, which can hide unrelated content. If the element is inside a frame or Shadow DOM, Playwright documents that screenshot styles pierce Shadow DOM and apply to inner frames; check that your selector matches the intended element in the actual page.
For a screenshot of just one element, the same capture-time stylesheet can be used with locator.screenshot():
await page.locator('#report').screenshot({
path: 'report.png',
style: '.print-controls { display: none !important; }',
});
See the [Playwright Page screenshot API](https://playwright.dev/docs/api/class-page) for screenshot options.
Hide dynamic elements in Playwright Test screenshot assertions
When using Playwright Test’s visual assertion API, put the CSS in a file and pass its path as stylePath. This filters changing elements from the screenshot used for comparison:
/* screenshot.css */
.cookie-banner {
display: none !important;
}
import { test, expect } from '@playwright/test';
test('page screenshot without the cookie banner', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot({
stylePath: 'screenshot.css',
});
});
Install the test runner with npm install -D @playwright/test, then run the test with npx playwright test. The file path is resolved by the test runner as part of the assertion options. This method is for Playwright Test assertions; for a direct screenshot, use page.screenshot({ style }).
More details are in the [Playwright screenshot assertion API](https://playwright.dev/docs/api/class-pageassertions) and [visual comparison guide](https://playwright.dev/docs/test-snapshots).
Options and related approaches
Masking does not hide an element
The screenshot mask option paints a colored overlay over a locator’s bounding box. It is useful for obscuring changing or sensitive content in a visual test, but the box remains visible in the image. Use the screenshot stylesheet when the element should disappear entirely.
await page.screenshot({
path: 'masked.png',
mask: [page.locator('.account-number')],
});
Playwright documents masking alongside the [Page screenshot options](https://playwright.dev/docs/api/class-page).
Use screenshot CSS for appearance-only changes
For a capture-only appearance change, CSS is the direct approach. You can add other CSS declarations to the same style string, for example to hide several selectors:
await page.screenshot({
path: 'clean.png',
style: `
.cookie-banner, .newsletter-modal, .chat-widget {
display: none !important;
}
`,
});
This changes how the capture is rendered. It does not remove the element from the page’s DOM or change the page’s application code.
Other runnable examples
cURL
Playwright’s screenshot stylesheet is a browser API, so it cannot be configured by a cURL request alone. To make the same capture through ScreenshotNeo’s API, send the CSS as a custom style option. See the [ScreenshotNeo documentation](https://screenshotneo.com/docs/) for the supported parameter name and request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
--data-urlencode 'css=.cookie-banner { display: none !important; }' \
-o screenshot.webp
Python with Playwright
Install the Python package and browser with pip install playwright and playwright install chromium:
import asyncio
from pathlib import Path
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
try:
await page.goto("https://example.com", wait_until="domcontentloaded")
await page.screenshot(
path="screenshot.png",
style=".cookie-banner { visibility: hidden !important; }",
full_page=True,
)
finally:
await browser.close()
asyncio.run(main())
Node.js API request
If you prefer a screenshot API over managing a browser, this Node.js example requests a ScreenshotNeo capture. For the API’s full options, use the [ScreenshotNeo docs](https://screenshotneo.com/docs/).
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com',
css: '.cookie-banner { display: none !important; }',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) => writeFile('screenshot.webp', image));
Or skip the browser setup
ScreenshotNeo is a website screenshot API: one GET request returns an image or PDF. Its capture options include custom CSS, and its [docs](https://screenshotneo.com/docs/) explain the available parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. [Learn about ScreenshotNeo](https://screenshotneo.com) or [create a free account](https://screenshotneo.com/account/sign-up/) to get 1,000 screenshots a month without a card.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The element is still visible. | The selector does not match it, or a page style overrides the rule. | Check the selector against the live page and add !important. Confirm the element is present when the screenshot is taken. |
| Content shifts after hiding the element. | The rule uses display: none, which removes the element from layout. |
Use visibility: hidden to keep its space. |
| A blank gap remains. | visibility: hidden hides the element but preserves its space. |
Use display: none if the surrounding content should close the gap. |
The page assertion rejects style. |
style is for direct screenshot capture; the test assertion uses a stylesheet path. |
Use stylePath: 'screenshot.css' with toHaveScreenshot(). |
| A colored rectangle appears where the element was. | The capture uses mask, which covers an element rather than hiding it. |
Use screenshot CSS with display: none or visibility: hidden. |
| The screenshot was taken before the element loaded. | The page or dynamic widget had not reached the state you expected. | Wait for a suitable selector or page state before capturing, then apply the capture stylesheet. |
Performance, reliability, and cost
A capture-time stylesheet avoids editing your application just to adjust a screenshot. Keep selectors specific and the rule set small, especially in repeated visual tests. The stylesheet controls visibility at capture time; it does not make a late-loading page or a changing application state deterministic by itself. Wait for the relevant page state before capture.
Playwright is a self-managed browser workflow: you install and run the browser and decide how to operate it. The documentation cited here describes the screenshot API, not a hosted capture price. A hosted API such as ScreenshotNeo can remove browser setup; its free tier includes 1,000 shots per month, and paid tiers begin at $5 for 3,000.
FAQ
Does the capture stylesheet permanently change the website?
No. The screenshot options apply CSS for the capture rather than adding a permanent style to the application page.
Which option should I use for a visual regression test?
Use toHaveScreenshot({ stylePath: 'screenshot.css' }) in Playwright Test. Use page.screenshot({ style }) for a direct capture.
Can screenshot styles affect elements in frames or Shadow DOM?
Playwright documents screenshot styles as piercing Shadow DOM and applying to inner frames. Verify the selector against the specific page structure you capture.
Can I hide an element with a locator alone?
For a persistent page change, locator actions or page-side code may alter the live page. For a capture-only change, use the screenshot stylesheet option.


