Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →In Playwright, a “JSON snapshot” normally means a stable JSON string compared with expect(value).toMatchSnapshot('name.json'). Playwright treats this as a generic text (or binary) snapshot; the .json extension simply keeps the baseline readable. If you need an accessibility tree as a JSON object, use page.ariaSnapshotJSON() instead. For accessibility template matching, use toMatchAriaSnapshot(), which stores YAML rather than JSON.
Choose the snapshot representation first
The right API depends on what you want to detect. A serialized API response, an accessibility tree, and a rendered page are different test artifacts.
| Need | Playwright API | Stored representation |
|---|---|---|
| Compare serialized JSON, text, or arbitrary data | expect(value).toMatchSnapshot('name.json') |
Text or arbitrary binary; you choose the extension |
| Read a page or locator accessibility tree as data | page.ariaSnapshotJSON() or the locator equivalent |
JSON value returned at runtime |
| Match accessibility structure against a maintained template | expect(page).toMatchAriaSnapshot(...) or locator form |
YAML template, normally an .aria.yml file |
| Whole-page visual regression | expect(page).toHaveScreenshot(...) |
PNG by default, or WebP when the name ends in .webp |
| Element visual regression | expect(locator).toHaveScreenshot(...) |
PNG or WebP baseline |
These APIs are not interchangeable. A JSON snapshot will not tell you whether pixels moved, and a screenshot will not give you a machine-readable response object.
Set up a generic JSON snapshot
Use the Playwright Test runner and keep the value deterministic before serializing it. This complete TypeScript test snapshots an API response:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
import { test, expect } from '@playwright/test';
test('API response remains stable', async ({ request }) => {
const response = await request.get('/api/settings');
const data = await response.json();
// Remove or normalize values that legitimately change between runs.
const stableJson = JSON.stringify(data, null, 2);
expect(stableJson).toMatchSnapshot('settings.json');
});
The first run creates a baseline in the test’s snapshot directory, commonly a directory such as example.spec.ts-snapshots. Commit that file so code review can show exactly what changed. The matcher compares text or arbitrary binary data; it does not parse JSON and apply a special JSON-aware diff.
Snapshot a browser-produced value
You can use the same matcher with data extracted from a page or locator:
import { test, expect } from '@playwright/test';
test('settings component data is stable', async ({ page }) => {
await page.goto('/settings');
const settings = await page.locator('[data-testid="settings"]').evaluate((el) => ({
theme: el.getAttribute('data-theme'),
language: el.getAttribute('data-language'),
notifications: el.getAttribute('data-notifications')
}));
expect(JSON.stringify(settings, null, 2))
.toMatchSnapshot('settings-component.json');
});
Give each artifact a specific name. If a test produces related snapshots, path segments in the name can keep them organized.
Make JSON deterministic before comparing it
Snapshot failures are useful only when they represent a meaningful product change. Normalize fields that are expected to vary:
- Replace timestamps with a fixed value or remove them.
- Redact random IDs, request IDs, tokens, and session-specific URLs.
- Sort arrays only when their order is not semantically meaningful.
- Format consistently with
JSON.stringify(value, null, 2)so diffs are readable. - Keep normalization in the test (or a shared helper) so the transformation is explicit during review.
function normalizeSettings(value: any) {
return {
...value,
updatedAt: '<normalized-time>',
requestId: '<normalized-request-id>',
users: [...(value.users ?? [])].sort((a, b) => a.id.localeCompare(b.id))
};
}
test('normalized settings', async ({ request }) => {
const data = await (await request.get('/api/settings')).json();
expect(JSON.stringify(normalizeSettings(data), null, 2))
.toMatchSnapshot('settings-normalized.json');
});
Do not sort or redact a field if its order or value is part of the behavior you are testing. A “stable” snapshot that hides a real regression is worse than a failing test.
Create and update baselines safely
Run the test normally to compare against an existing baseline. To create a missing baseline or intentionally accept a reviewed change, run:
npx playwright test --update-snapshots
# short form
npx playwright test -u
The update flag changes mismatching snapshots; matching snapshots are not rewritten. Review the resulting diff and commit only changes caused by an intentional product or contract update. Avoid routinely running the update command in CI, because it can silently replace the expected result.
Control where snapshots are stored
For an individual test, test.info().snapshotPath() resolves paths for ordinary, screenshot, and accessibility snapshot kinds. A repository can define a project-wide or assertion-specific snapshotPathTemplate when the default layout does not fit. Supported template tokens include {testFilePath}, {arg}, {ext}, {platform}, and {projectName}.
Free tools Windows power users keep installed
One-click scans. No signup required.
import { test, expect } from '@playwright/test';
test('reports the baseline location', async ({ request }) => {
const data = await (await request.get('/api/settings')).json();
const name = 'settings.json';
expect(JSON.stringify(data, null, 2)).toMatchSnapshot(name);
console.log(test.info().snapshotPath(name));
});
Keep snapshot layout predictable across projects. Platform- or project-specific tokens are useful when the same test intentionally has different baselines.
Use JSON accessibility snapshots correctly
ariaSnapshotJSON() is for an accessibility tree represented as a JSON value. It is different from a generic serialized-value snapshot:
Rank #3
import { test, expect } from '@playwright/test';
test('navigation accessibility data', async ({ page }) => {
await page.goto('/');
const tree = await page.ariaSnapshotJSON();
expect(JSON.stringify(tree, null, 2))
.toMatchSnapshot('home-aria.json');
});
The locator form lets you scope the tree to one component. When you want Playwright to match an accessibility template directly, use toMatchAriaSnapshot() instead. That assertion uses YAML templates (stored in an .aria.yml file by default), so it should not be described as a JSON-file matcher. Choose JSON when another tool needs the runtime object; choose the YAML assertion when the template itself is the test contract.
Do not use JSON snapshots for visual regression
For rendered pixels, use toHaveScreenshot():
import { test, expect } from '@playwright/test';
test('dashboard visual baseline', async ({ page }) => {
await page.goto('/dashboard');
await expect(page).toHaveScreenshot('dashboard.png');
await expect(page.locator('[data-testid="chart"]'))
.toHaveScreenshot('chart.webp');
});
Playwright waits for two consecutive screenshots to stabilize before comparing. Screenshot assertions support controls such as animation disabling, masking dynamic regions, style paths, and pixel-difference thresholds. Generate and review visual baselines in the same browser, operating-system, dependency, and rendering environment because rendering varies between hosts. A JSON snapshot of DOM-derived data cannot substitute for this pixel-level check.
Troubleshoot common failures
“Snapshot does not exist”
Run the specific test once with npx playwright test path/to/test.spec.ts -u, inspect the generated file, and commit it. Confirm that the test is running from the expected project and snapshot directory.
Every run changes the JSON
Look for timestamps, random identifiers, request IDs, generated ordering, locale-dependent formatting, or data returned in nondeterministic order. Normalize only fields that are not part of the contract, then serialize with consistent indentation.
The diff is unreadable
Snapshot the formatted string rather than a compact one-line string: JSON.stringify(value, null, 2). Split unrelated response areas into named snapshots when one huge artifact obscures the cause.
The test passes locally but fails in CI
Check environment-dependent data, browser and dependency versions, locale, timezone, and the service data used by the test. For visual assertions, align the browser, operating system, dependencies, and rendering environment; for JSON, remove only genuinely volatile fields.
Updating snapshots removed an intentional guard
Inspect the diff before accepting it. Revert the baseline and fix the implementation if the change was not planned. Treat snapshot files as source code, not disposable test output.
An accessibility assertion has the wrong file type
Use ariaSnapshotJSON() when you need a JSON value. Use toMatchAriaSnapshot() for the YAML-template assertion. A generic toMatchSnapshot('file.json') call will compare whatever string or bytes you pass; it does not convert a YAML accessibility template into JSON.
Performance, reliability, and review practices
- Snapshot the smallest stable value that answers the test question instead of an entire page object.
- Reuse a normalization helper so all tests handle volatile fields consistently.
- Keep baselines beside the test’s snapshot directory and commit them with the change that intentionally updates behavior.
- Run focused tests while developing, then run the full suite before merging to detect interactions between shared fixtures and contracts.
- Use API or accessibility JSON snapshots for semantic changes and visual snapshots only where layout or rendering is the requirement.
- Never approve a blanket
-uupdate without reading the diff; it can encode an accidental regression as the new expectation.
Or skip the browser setup
If your goal is a clean image or PDF of a URL rather than a Playwright test baseline, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for all options. The same request in Python is:
Recommended Free Tools
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)
And in Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and whether the request was billed.
- An MCP server exposes
take_screenshot,get_page_info, andcapture_pdfto Claude, Cursor, and other MCP clients. - Options include full-page capture with lazy images, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper settings and page ranges, custom CSS and JavaScript, clicks, selector or network-idle waits, request/resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration.
The Free plan includes 1,000 shots per month with no card. Paid plans are Starter $5 for 3,000 shots, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to get the 1,000 monthly shots without a card.
FAQ
Can the snapshot name include a directory?
Yes. Pass a path such as api/settings.json as the snapshot name when grouping related artifacts helps your repository layout.
Does Playwright parse the JSON and ignore property order?
No. The generic matcher compares the serialized text or bytes you provide. Normalize and serialize the value yourself when ordering or formatting should be controlled.
Should accessibility JSON and visual screenshots be in the same test?
Only when the test genuinely covers both contracts. Keeping semantic-data and pixel assertions separate usually makes failures easier to diagnose and baselines easier to review.
Frequently Asked Questions
Can the snapshot name include a directory?
Yes. Pass a path such as api/settings.json as the snapshot name when grouping related artifacts helps your repository layout.
Does Playwright parse the JSON and ignore property order?
No. The generic matcher compares the serialized text or bytes you provide. Normalize and serialize the value yourself when ordering or formatting should be controlled.
Should accessibility JSON and visual screenshots be in the same test?
Only when the test genuinely covers both contracts. Keeping semantic-data and pixel assertions separate usually makes failures easier to diagnose and baselines easier to review.
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.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →

