Playwright Screenshot Test Says Image Size Differs: How to Fix It
Fix Playwright screenshot size mismatches by checking viewport, device scale, capture scope, and browser environment before updating a baseline.
If a Playwright screenshot test says the image size differs, first make the expected and actual captures use the same browser environment, viewport, device scale factor, screenshot scale, and capture scope. Check whether the test captures the viewport, the full page, or a clipped region. Only update the baseline after confirming the UI change is intentional; comparison thresholds do not fix different image dimensions.
The error alone does not identify which setting differs. Compare the reported expected and actual width × height, then inspect both image artifacts and the capture configuration.
1. Read the failure and inspect both images
Start with the complete assertion output. Record the expected and actual pixel dimensions, and locate the expected snapshot and actual screenshot artifact. Playwright’s snapshot workflow usually provides a diff image as well; inspect the three files together to distinguish a capture-size mismatch from a visual change.
- If width and height both differ by the same factor, check device scale factor and screenshot
scale. - If width matches but height differs, check viewport height,
fullPage, page content or a clip rectangle. - If the dimensions match but pixels differ, investigate rendering environment, fonts, dynamic content, and comparison tolerance separately.
These are diagnostic clues, not proof of a specific cause. Use the actual project and assertion settings to identify the mismatch.
2. Make the browser environment consistent
Visual output can vary with the host operating system, browser version, browser settings, hardware, power source, and headless mode. Generate and compare baselines in a consistent environment where practical. Pinning the Playwright version and using the same browser installation and operating system for baseline generation and CI comparisons helps reduce environment-related differences. See Playwright’s visual comparisons guide.
Also check that CI and local runs use the same Playwright project. A test that runs in Chromium locally but a different browser project in CI may have different capture conditions and rendering.
3. Match viewport and device emulation
Check the configured browser context viewport, device descriptor, and any page-level setViewportSize() call. Device descriptors can set a viewport and device scale factor. If you spread a device descriptor and then want to override its viewport, put the explicit viewport after the spread:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
viewport: { width: 1280, height: 720 },
},
},
],
});
The 1280 × 720 dimensions are an example. Choose the viewport your application is meant to test. Reordering options matters: a later value overrides an earlier one. Review the official emulation guide for device configuration and viewport overrides.
Search the test and fixtures for calls to page.setViewportSize() that could change the viewport after the browser context is created. Make sure the baseline was generated with the same final viewport used by the assertion.
4. Match screenshot scale and capture scope
Playwright screenshot options affect the output dimensions:
scale: 'css'produces one screenshot pixel per CSS pixel.scale: 'device'uses device pixels, so output dimensions can grow with a high device scale factor.fullPage: truecaptures the full scrollable page instead of only the viewport.cliprestricts capture to the specified rectangle.
Set these deliberately and keep them the same for baseline creation and comparison. For screenshot assertions, configure the assertion directly:
import { test, expect } from '@playwright/test';
test('page screenshot', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('page.png', {
fullPage: false,
scale: 'css',
});
});
Use fullPage: true if the test is intended to cover the whole document. If it uses a clipped region, provide the same clip rectangle for every capture. Consult the official Page screenshot API and PageAssertions API for supported options.
5. Update a baseline only for an accepted UI change
Once capture conditions match, decide whether the new rendering is an intentional product change. If it is, review the screenshot and then regenerate the snapshot:
npx playwright test --update-snapshots
Review the changed snapshots in version control before accepting them. If the rendering change is unexpected, fix its cause instead of replacing the expected image.
Options such as maxDiffPixels, maxDiffPixelRatio, and threshold control visual comparison tolerance. They do not make differently sized images the same size. Adjust tolerances only when dimensions already match and the remaining pixel differences are acceptable for that test. See Playwright’s SnapshotAssertions API.
6. Troubleshooting checklist
| Symptom | Likely setting to inspect | Fix |
|---|---|---|
| Actual image is larger in both dimensions | Device scale factor or scale: 'device' |
Use the same device emulation and screenshot scale as the baseline; consider scale: 'css' when CSS-pixel output is intended. |
| Only image height differs | Viewport height, fullPage, page content, or clip |
Match the viewport and assertion scope. Check whether the page’s scrollable content changed. |
| Image width differs after adding a device preset | Preset viewport overridden or applied in a different order | Inspect the final project configuration; put an intended explicit viewport after the device spread. |
| Local run passes but CI fails | Host OS, browser version, headless mode, project, or device settings | Run baseline and comparison in a consistent environment and verify CI uses the same project and browser setup. |
| Dimension error remains after changing tolerance | Capture configuration still differs | Restore the relevant tolerance if it was changed, then align viewport, scale, scope, and clip. Tolerance is not a dimension repair. |
| Updated snapshot hides a regression | Baseline refreshed without reviewing the visual change | Restore the old baseline if needed, identify the source of the visual change, and update only after review. |
7. Reliability and runtime considerations
Keep screenshot inputs deterministic where possible: use a fixed viewport and project, avoid changing device emulation mid-test, and make capture scope explicit. Full-page captures include more page content and can take longer or vary when content loads dynamically. Wait for the page state your test actually needs before capturing, and avoid regenerating baselines in a different environment from the one used for review.
For a mismatch investigation, preserve the failure artifacts and compare their dimensions before changing configuration. This gives you a reproducible starting point and prevents a tolerance adjustment or baseline refresh from masking the original cause.
Or skip the browser setup
If you need a website capture outside a Playwright test, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for request options.
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
ScreenshotNeo accepts cookie or consent banners like a visitor 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, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Will maxDiffPixels fix an image size mismatch?
No. It affects pixel-difference tolerance after the capture dimensions match.
Should I always use scale: 'css'?
No. Use the scale that matches what the test is meant to verify, and use it consistently for expected and actual screenshots.
Should I update snapshots whenever CI fails?
No. First check dimensions and capture conditions, then review whether the visual change is intentional before updating the baseline.


