Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To change a website’s appearance only in a Playwright screenshot, pass CSS through the screenshot’s style option; for a Playwright Test visual assertion, use stylePath. If the change should remain active for later page actions—or you are using Puppeteer—inject a stylesheet with page.addStyleTag(), then capture. The key choice is whether your CSS is temporary capture styling or a change to the page itself.

Choose the right CSS method

Method Use it for Where the CSS applies
Playwright Test stylePath Visual regression assertions with toHaveScreenshot() During the screenshot assertion; accepts one stylesheet path or an array of paths
Playwright page.screenshot({ style }) A direct Playwright screenshot with a one-off CSS override For the screenshot operation
Playwright or Puppeteer page.addStyleTag() CSS that should remain in effect for subsequent page steps Inserted into the document as a style element or linked stylesheet

Playwright documents stylePath for screenshot assertions, including hiding volatile elements, piercing Shadow DOM, and applying styles to inner frames. It was added in Playwright v1.41; check the documentation for the version installed in your project: Playwright visual comparisons. The direct Page API options are documented at Playwright Page API.

Apply CSS to a Playwright Test screenshot assertion

Use stylePath when your test uses Playwright Test’s toHaveScreenshot() assertion and you want the stylesheet to affect the visual comparison without becoming an application styling change. Save a stylesheet next to your test, then pass its path to the assertion.

Test file

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

test('page screenshot ignores the changing chat widget', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveScreenshot({
    stylePath: path.join(__dirname, 'screenshot.css'),
  });
});

screenshot.css

/* Hide a changing widget that is irrelevant to this visual assertion. */
.live-chat-widget {
  visibility: hidden !important;
}

For projects targeting environments where __dirname is unavailable, use the path convention supported by your module system, such as an absolute path derived from import.meta.url. The essential API choice remains stylePath; its value can be a stylesheet file name or an array of file names.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Apply CSS to a direct Playwright screenshot

For a regular screenshot rather than a Test assertion, put stylesheet text in the style option. This is the shortest route for capture-only changes such as hiding a volatile timestamp or chat control.

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();

try {
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  await page.screenshot({
    path: 'capture.png',
    fullPage: true,
    style: '.live-chat-widget { visibility: hidden !important; }',
  });
} finally {
  await browser.close();
}

The example uses domcontentloaded as a navigation milestone, not a promise that every image, font, or asynchronous component is ready. If the page content you need appears later, wait for a meaningful selector or other page-specific readiness condition before capturing.

Inject CSS into the page with Playwright

Use page.addStyleTag() when later operations should see the altered page state—for example, if you will inspect the page after the screenshot or take several captures with the same styling. The API accepts CSS text through content, as well as path or URL inputs.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();

try {
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  await page.addStyleTag({
    content: '.live-chat-widget { visibility: hidden !important; }',
  });
  await page.screenshot({ path: 'capture.png' });
} finally {
  await browser.close();
}

To load an existing stylesheet instead, use the supported path or url input to addStyleTag(). Remember that this inserts styling into the live document, unlike screenshot-scoped CSS.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Inject CSS and capture with Puppeteer

Puppeteer does not use Playwright’s screenshot style or Test stylePath options. Insert a style tag into the page, then call the screenshot API:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();

try {
  await page.goto('https://example.com', { waitUntil: 'networkidle2' });
  await page.addStyleTag({
    content: '.live-chat-widget { visibility: hidden !important; }',
  });
  await page.screenshot({ path: 'capture.png', fullPage: true });
} finally {
  await browser.close();
}

Puppeteer’s guide demonstrates networkidle2 as one navigation option, but it is not the right readiness rule for every site. A page can keep background requests open, or finish network activity before the particular content you need is rendered. Puppeteer documents addStyleTag() at Page.addStyleTag() and capture methods in its screenshots guide.

Write CSS that stabilizes the image without hiding its meaning

Use a selector that targets only the element you mean to alter. A narrow selector makes it less likely that a site redesign or reused class will hide important content elsewhere. Add !important when page styles otherwise override the masking rule.

  • Hide an irrelevant widget: .live-chat-widget { visibility: hidden !important; } preserves its layout space while making it invisible.
  • Remove it from layout: use display: none !important; when the widget’s reserved space also makes the capture inaccurate. This can shift neighboring content, so choose deliberately.
  • Target only a changing value: mask a timestamp or rotating ad rather than hiding the whole section around it.
  • Preserve the content being evaluated: suppress only noise irrelevant to the screenshot, such as transient overlays or a live clock. Do not hide page content that a reviewer needs to see.

Playwright’s screenshot stylesheet is specifically documented as a way to hide dynamic or volatile elements and improve screenshot determinism. The same CSS can still produce different pixels if the underlying browser, operating system, settings, hardware, power source, or headless mode changes. For meaningful visual comparisons, keep the rendering environment consistent; see Playwright’s visual comparison guidance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for the right page state before capture

CSS injection changes styling; it does not make a page ready. Navigation completion alone may not mean the key image, web font, client-rendered section, or delayed content has appeared. Identify what must be present and wait for it before capturing:

await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('main article').waitFor({ state: 'visible' });
await page.screenshot({
  path: 'capture.png',
  style: '.live-chat-widget { visibility: hidden !important; }',
});

Replace the selector with an element that represents the content you actually need. For pages whose important state is driven by an interaction, perform that interaction and wait for its result before the screenshot. Network-idle waits can be useful on some pages, but they are not universally sufficient or guaranteed to finish on pages with ongoing requests.

Capture a particular element instead of the whole page

If the target is a component rather than the whole document, capture its element after applying the same CSS method described above. Puppeteer supports an element handle’s screenshot method; Playwright offers locator screenshots. This can make the output more focused, but the selected element must be visible and laid out before capture.

// Playwright
await page.locator('.product-card').screenshot({ path: 'product-card.png' });

When using screenshot-scoped CSS, ensure its selector still matches elements inside the region being captured. If you use an injected stylesheet, it remains part of the page for subsequent actions unless you remove or replace it.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot CSS screenshot problems

  • The target remains visible. Check that the selector matches the live page, including capitalization and state-dependent classes. Inspect the element in the browser or query it with page.locator('.live-chat-widget').count(). A more specific rule or !important may be needed if the site overrides your declaration.
  • The rule works in a direct capture but not a test assertion. Make sure you are using stylePath inside Playwright Test’s toHaveScreenshot(), not as an option to an unrelated screenshot method. For a direct Page screenshot, use its style option.
  • The page changes after the screenshot. A stylesheet inserted by addStyleTag() changes document state. If only the image should change, use Playwright’s screenshot-scoped option instead.
  • Styles do not reach an embedded or shadowed element. Playwright documents screenshot styles as piercing Shadow DOM and applying to inner frames. For a different API or setup, verify the element’s context and whether your selector can reach it; ordinary document CSS may not select into every isolated context.
  • Content is missing or still loading. Wait for the specific content or state needed before taking the screenshot. CSS cannot force a late image or client-rendered component to load.
  • Visual diffs remain across machines. Match the browser version and rendering environment used for the baseline. CSS does not remove variation caused by operating system, settings, hardware, or headless mode.
  • The image has unexpected blank space. visibility: hidden leaves the element’s layout footprint. Switch to display: none only if collapsing that space is appropriate.

Or skip the browser setup

If you need a screenshot from code without managing a browser session, ScreenshotNeo is a website screenshot API and MCP server. Its API accepts one GET request with a URL and returns an image or PDF; custom CSS and JavaScript are among its capture options. API details and the full parameter reference are in the ScreenshotNeo documentation.

curl -G "https://api.screenshotneo.com/v1/shot" 
  -d access_key=YOUR_API_KEY 
  --data-urlencode url=https://example.com 
  --data-urlencode 'css=.live-chat-widget { visibility: hidden !important; }' 
  -o shot.webp

Use your API key in place of YOUR_API_KEY. The request above demonstrates the API call and CSS parameter; consult the documentation for the current accepted parameter names and response options. ScreenshotNeo removes cookie/consent banners, newsletter popups, and chat widgets before capture; each of those cleanup steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Start at ScreenshotNeo’s free sign-up.

FAQ

Can I use a CSS file instead of writing CSS in the test?

Yes. For a Playwright Test screenshot assertion, point stylePath at a CSS file; it also accepts an array of stylesheet paths.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does screenshot CSS change the website for other visitors?

No. These methods apply styling in the browser session used for your capture; they do not edit the site’s deployed source files.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.