Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
If a Playwright screenshot passes in headed mode but fails headless, make the two runs genuinely identical before changing your assertions. Use the same OS or container image, Playwright and browser builds, fonts, locale, timezone, viewport, device scale, screenshot scale, animation state, page data and capture options. Headless mode itself is only one variable in a larger rendering environment.
Why headed and headless screenshots differ
Playwright’s visual-comparison guidance is explicit: “For consistent screenshots, run tests in the same environment where the baseline screenshots were generated.” Rendering can vary with the host operating system, browser version, browser settings, hardware, power source, headless mode and other environmental details. Snapshot names also encode browser and platform because fonts and rendering differ across browsers and operating systems.
A headed run may therefore be compared with a baseline created on a different machine, browser build or font set. The test intent can be correct while the pixels are not comparable. There is no authoritative universal percentage for how often headed and headless images differ, nor a single pixel threshold that fixes every project.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use one deterministic environment
Pin the operating system and container
Create the baseline and execute comparisons in the same container image or OS installation. Keep the CPU architecture and installed system libraries consistent where possible. In CI, use one pinned image for baseline generation and verification instead of generating baselines on a developer laptop and comparing them on a different Linux image.
#1 Best Overall
Pin Playwright and browser versions
Lock the Playwright package in your package manager and install the browser build associated with that lockfile. A package update can bring a different browser revision, and even a browser update that appears minor can change text shaping, antialiasing or layout. Regenerate baselines deliberately when you intentionally upgrade.
Install the same fonts
Font fallback is a frequent source of changed line breaks and element dimensions. Install the same font files in both environments, verify that the required weights exist, and avoid relying on whatever fonts happen to be present on a workstation. A missing web font can also produce a different first paint, so wait for the page’s intended font-loading state before capture.
Hold locale and timezone constant
Dates, numbers, translated strings and locale-specific font behavior can alter pixels. Configure the same locale and timezone in headed and headless projects, and make test data deterministic. Do not let the runner inherit a developer’s local timezone while CI uses UTC.
Free tools Windows power users keep installed
One-click scans. No signup required.
Fix viewport, device density and screenshot scale
Set an explicit viewport and device scale factor
Do not rely on a headed window’s current size or a CI default. Set the context viewport and deviceScaleFactor explicitly. Playwright’s emulation controls also cover screen size, user agent, touch behavior and related device properties; keep any values that affect responsive layout identical in both modes.
import { chromium } from '@playwright/test';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1,
locale: 'en-US',
timezoneId: 'UTC'
});
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'headed-equivalent.png', fullPage: true, scale: 'css' });
await browser.close();
The exact values are project decisions; the important property is that the same values are used for baseline and comparison. A high-density headed display and a one-device-pixel headless context will not produce equivalent image dimensions unless you choose and hold the same density and scale.
Keep scale identical
Playwright’s screenshot scale option accepts "css" or "device". CSS scale emits one image pixel per CSS pixel. Device scale emits one pixel per device pixel and can make high-DPI images larger. Select one and use it in both runs. A mismatch here can look like a broad layout failure even when the page layout is correct.
Rank #2
Freeze animation and transient page state
Disable animations during assertions
Screenshot assertions default animations to "disabled". Finite animations are fast-forwarded and infinite animations are canceled for the capture. Preserve that default or set it explicitly. If your application starts transitions outside the assertion, inject a screenshot-only stylesheet that disables transitions and animations.
Hide the caret and mask changing data
A blinking text caret, clock, rotating banner, random identifier, advertisement or third-party widget can create a diff unrelated to headed/headless execution. Use caret: "hide", mask dynamic locators, and apply a screenshot stylesheet with the style or stylePath options. Mask only content that is intentionally nondeterministic; masking a real regression hides useful evidence.
import { test, expect } from '@playwright/test';
test('stable visual', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('home.png', {
animations: 'disabled',
caret: 'hide',
scale: 'css',
fullPage: true,
mask: [page.locator('[data-testid="live-clock"]')],
style: `
*, *::before, *::after {
transition: none !important;
animation: none !important;
caret-color: transparent !important;
}
`
});
});
Wait for the same application state
Use the same readiness condition in both modes: a required selector, a stable data fixture or an explicit network condition. Avoid arbitrary sleeps when a selector communicates readiness more precisely. If a page fetches time-sensitive data, stub it or serve a fixed fixture so headed and headless executions receive identical content.
Make capture scope and options match
Decide whether the test captures the viewport, one element or the entire page, then use the same choice everywhere. Keep fullPage, clip, element locator, image format, quality, caret, mask, style, stylePath and scale consistent. A headed screenshot of a visible viewport compared with a headless fullPage screenshot is not a mode comparison; it is a different capture.
- Viewport: captures the currently configured viewport.
- Element: captures the same locator after it is visible and stable.
- Full page: captures the complete scrollable page; lazy content must be loaded consistently.
- Clip: uses the same coordinates and dimensions in the same viewport.
When a page uses lazy loading, scroll or otherwise trigger the same loading behavior before capture. Otherwise, a full-page image can differ simply because one run loaded images that the other never requested.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →A reliable comparison order
- Confirm the OS or container image is identical.
- Confirm the Playwright package and browser engine build.
- Compare installed fonts and available font weights.
- Compare viewport width and height, user agent and device scale factor.
- Compare screenshot scale, viewport versus full-page scope and clipping.
- Compare locale, timezone and test data.
- Disable animations, hide the caret and mask only known dynamic regions.
- Inspect network responses, lazy loading and third-party widgets.
- Only after deterministic causes are eliminated, review the comparator threshold.
Do not relax a diff threshold as the first response. A permissive threshold can conceal a real font, layout or content regression. Change it only when you understand the remaining rendering variance and have chosen an explicit project policy.
Troubleshooting common failures
Text wraps differently
Check font installation, font loading, viewport width, device scale and browser revision. Verify that the same weight is available rather than silently falling back. Wait for the application’s font-ready state before taking the screenshot.
Only shadows, edges or text antialiasing differ
These details can reflect OS, graphics hardware, browser build or device scale. Move both jobs to the same container and keep scale consistent. Do not assume a threshold is appropriate until the environments match.
A header, menu or modal is at a different position
Compare viewport dimensions and responsive breakpoints, then check whether a headed window has been resized by the desktop environment. Ensure the same navigation steps, cookies and authentication state are applied in both runs.
A blinking cursor or spinner appears in one image
Set caret: "hide", disable animations and wait for a stable selector. For an intentionally live region, mask its locator or replace its data with a fixture.
Full-page images have different heights
Look for lazy-loaded content, expanding images without fixed dimensions, delayed fonts, ads or chat widgets. Trigger the same scroll/loading sequence and remove or stub third-party content. Confirm that both captures use fullPage: true rather than one using a viewport clip.
The screenshot is blank or incomplete
Check navigation errors, authentication, blocked resources and the readiness condition. A fast headless run can capture before application hydration; wait for a meaningful selector rather than adding an unexplained delay.
CI fails but local headless passes
CI is a different rendering environment. Compare its image, fonts, browser revision, locale, timezone, viewport, hardware and power-related settings with the local run. Reproduce inside the CI container and generate the baseline there.
Rank #4
Performance, reliability and maintenance
Determinism usually improves speed because stable readiness checks replace repeated retries. Reuse a browser process where your test architecture permits it, but create isolated contexts with explicit settings so one test cannot leak cookies, locale or viewport into another. Keep screenshot-only CSS small and version-controlled. Store baselines with the browser and platform identity they require, and review them intentionally after environment upgrades.
Use a fixed test dataset and control external services. Third-party ads, consent tools, chat clients and analytics can change independently of your code; block or stub them when they are not part of the visual contract. If they are part of the contract, pin the state you expect and accept that the dependency must be maintained.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
For one-off captures, documentation images or a service that should return an image without maintaining Playwright, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers.
The API supports PNG, JPEG, WebP and PDF output, full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and margin controls, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for selectors, delays or network idle, request and resource blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Its parameter names also accept the names used by other screenshot APIs, which can simplify migration. An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
Call it with one request (see the ScreenshotNeo documentation):
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}`);
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan, and yearly billing gives two months free. Sign up free to start without a card.
FAQ
Is headless mode inherently lower quality?
No. Differences generally come from the complete execution environment and capture settings, not from the headed label alone. Matching those variables is the remedy.
Should I keep separate baselines for headed and headless runs?
Use one baseline when the environments and options are intentionally identical. Keep separate baselines only when the target environments are deliberately different and each image represents a supported rendering target.
Recommended Free Tools
Which screenshot scale should a team choose?
Choose css for one pixel per CSS pixel or device for device-pixel output, then apply that choice consistently. The right option depends on what your review system and consumers expect.
Frequently Asked Questions
Is headless mode inherently lower quality?
No. Differences generally come from the complete execution environment and capture settings, not from the headed label alone.
Should I keep separate baselines for headed and headless runs?
Use one baseline when environments and options are intentionally identical; separate baselines are appropriate only for deliberately different supported targets.
Which screenshot scale should a team choose?
Choose CSS-pixel or device-pixel output based on your consumers, and use that choice consistently in every run.
Quick Recap
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.

