How to Compare Full-Page Website Screenshots After a CMS Content Update
Capture a stable before-and-after baseline, compare the full page, and tell intended CMS edits from visual regressions with a repeatable Playwright workflow.
To compare a full-page website screenshot after a CMS content update, save an approved screenshot of the page before the change, capture the same URL afterward in the same browser and viewport, and compare the two images. Review every difference against the planned edit: a pixel difference shows that the page changed, but it cannot tell you whether the change is correct.
This guide uses Playwright to capture and compare screenshots locally. It covers baseline setup, full-page captures, volatile content, difference review, and a hosted review option. For functional checks such as links, text, and publishing state, use separate assertions; screenshots alone do not establish that the content or behavior is correct.
1. Prepare a reproducible comparison
Before changing the CMS content, choose a stable page state and record how to reproduce it. A useful comparison keeps the URL, browser version, operating system, viewport, device scale, fonts, test data, and relevant page state consistent. Rendering can vary across host operating systems, browser versions, settings, hardware, power source, and headless mode, so changing environments between captures can create noise. Playwright documents these sources of screenshot variation.
- Choose a URL that resolves to the same page and environment in both runs. Include locale, query parameters, authentication, and other state if they affect the page.
- Record the intended CMS change. For example: “Replace the hero image and add a paragraph below the introduction.”
- Use a consistent viewport and browser configuration. Keep fonts and test data stable.
- Identify genuinely volatile regions, such as a rotating promotion or live timestamp. Decide whether to stabilize, hide, or mask them; do not suppress areas that need review.
- Capture and approve the baseline before publishing the update. Keep it associated with the page state and environment that produced it.
Playwright creates reference screenshots on the initial run and compares later runs against them. Its snapshot files are tied to platform and browser details, so use the same environment for meaningful comparisons. See Playwright’s visual comparison documentation.
2. Install Playwright and create a full-page baseline
The following example uses Node.js and Playwright Test. It captures the page from a supplied environment variable, waits for fonts, and creates a full-page reference screenshot. Run it against the page before the CMS update, review the image, and retain the approved snapshot with the test suite.
npm init playwright@latest
Choose JavaScript when prompted, then replace or create tests/cms-page.spec.js:
const { test, expect } = require('@playwright/test');
test('CMS page matches the approved full-page baseline', async ({ page }) => {
const url = process.env.PAGE_URL;
if (!url) throw new Error('Set PAGE_URL to the page you want to capture');
await page.setViewportSize({ width: 1440, height: 1000 });
await page.goto(url, { waitUntil: 'networkidle' });
await page.evaluate(() => document.fonts.ready);
await expect(page).toHaveScreenshot('cms-page.png', {
fullPage: true,
animations: 'disabled',
maxDiffPixels: 0,
});
});
Set the URL and create the initial reference:
PAGE_URL=https://example.com/article npx playwright test tests/cms-page.spec.js --update-snapshots
Inspect the generated baseline before treating it as approved. Commit the reference screenshot and test together if your team stores visual baselines in source control. The exact snapshot location depends on Playwright’s project and platform configuration.
3. Capture and compare after the CMS update
After publishing or applying the content change, rerun the same test without the snapshot update flag. Playwright compares the new render with the approved reference and reports a failure when it differs beyond the configured threshold.
PAGE_URL=https://example.com/article npx playwright test tests/cms-page.spec.js
Review the test output and generated actual, expected, and diff images. First inspect the whole page to find shifted sections or missing lower-page content; then zoom into changed regions. A full-page capture includes content below the fold, which gives wider visual coverage than checking only the initial viewport. BrowserStack’s Percy guidance recommends verifying the entire page.
For each changed area, ask:
- Does the difference correspond to the planned CMS edit?
- Does the new text wrap as expected, without clipping or unexpected overflow?
- Did images load and keep their intended crop, dimensions, and position?
- Did spacing, headings, navigation, calls to action, or lower-page sections move unexpectedly?
- Is the change consistent at the viewport and page state this baseline represents?
Only update the reference after review confirms that the new appearance is intentional. Updating a baseline accepts the new image as the expected state; it is not itself evidence that the page is correct.
4. Control screenshot noise carefully
Dynamic content can make otherwise identical captures differ. First try to make the page deterministic: use fixed test data, a stable URL, a known logged-in state, and a wait condition tied to the content that matters. If a specific element is inherently variable, use a narrowly scoped capture-time stylesheet to hide it.
await expect(page).toHaveScreenshot('cms-page.png', {
fullPage: true,
animations: 'disabled',
style: `
.live-clock,
[data-visual-test="volatile"] {
visibility: hidden !important;
}
`,
maxDiffPixels: 20,
});
Playwright documents capture-time styling for filtering dynamic regions and comparison controls including maxDiffPixels and a per-pixel threshold. Keep any ignored selector and threshold as narrow as practical. A broad mask or tolerance can conceal a broken layout or an unintended content change. Review the available screenshot assertion options.
When a CMS update intentionally changes copy, the difference image will naturally show changed pixels. Do not raise a threshold simply to make the assertion pass. Review the changed content, decide whether it is expected, and then approve a new baseline if appropriate.
5. Choose local assertions or hosted review
| Workflow | How it handles the comparison | Fits when |
|---|---|---|
| Local Playwright assertions | Reference snapshots live with the test suite; a changed screenshot fails the assertion and can be reviewed with test output and repository changes. | Your team already uses Playwright and wants to manage baselines in source control. |
| Hosted Percy review | Build snapshots are compared against a baseline in the Percy project, where reviewers inspect visual changes. BrowserStack documents broader browser and responsive-width coverage, and an approval-oriented review flow. | Your team wants hosted change review or documented browser and viewport breadth, and is prepared to configure the integration. |
These workflows do not infer editorial intent. In either case, a reviewer must determine whether a visual change matches the CMS update. If unapproved visual changes should block delivery, configure the relevant pipeline gate for your workflow. Read the Percy visual testing overview and Percy’s Playwright integration reference for its documented review and integration flow.
6. Keep visual checks separate from content and behavior checks
A screenshot comparison detects rendering differences. Add separate checks for requirements that pixels cannot establish reliably:
- Assert the expected heading or edited copy is present.
- Check that important links point to the intended destinations.
- Verify the CMS published the intended content and locale.
- Exercise interactions such as menus, accordions, forms, and calls to action if they are in scope.
This makes a visual review more useful: screenshot differences tell you where the rendering changed, while functional and content assertions check whether the page still meets its requirements. Percy’s guidance also treats visual checks as part of a broader verification process.
7. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Many pixels differ on every run | The browser, operating system, fonts, viewport, device scale, or page data changed between runs. | Restore the baseline environment and page state. Use a stable browser installation, fixed viewport, and consistent test data. |
| Only timestamps, ads, or rotating content differ | The page contains volatile content that changes independently of the CMS edit. | Stabilize the data if possible. Otherwise hide or mask only the known volatile region with a narrowly scoped rule. |
| The screenshot is blank or incomplete | The page may not have finished loading, may require authentication, or may have failed before the target content rendered. | Check navigation errors and authentication, then wait for a meaningful page element or state before capturing. Do not approve a blank image as a baseline. |
| Images or lower sections are missing | Lazy-loaded content may not have entered the render area or the full-page capture was not used. | Confirm fullPage: true, wait for the relevant content and fonts, and check whether the page requires scrolling or interaction to load sections. |
| Expected CMS text changes cause a failing assertion | The baseline still represents the pre-update copy. | Review the diff against the planned edit. If the new page is correct, update the baseline and include that change for review. |
| A small threshold makes the test pass but hides a defect | The allowed difference is too broad or the ignored region covers meaningful content. | Reduce the threshold, remove broad masks, and inspect the diff. Apply tolerance only for known rendering variation. |
| Comparison differs between local and CI | The environments render differently or the CI job uses different browser binaries, fonts, or settings. | Run capture and comparison in the same pinned environment. Keep baseline generation and CI configuration aligned. |
8. Performance, reliability, and cost considerations
A full-page screenshot captures more content than a viewport screenshot, so it can take longer and produce a larger image, especially on long pages. Keep the comparison focused on the page and state that matter. Avoid unnecessary repeated captures, and use a stable wait condition rather than an arbitrary long delay when you can identify the content that signals readiness.
Reliability depends on controlling the render environment and page state. Preserve approved baselines, review baseline changes, and avoid regenerating references automatically after every failure. A changed image should prompt investigation; it should not be silently accepted.
Local Playwright screenshot assertions use your test environment and snapshot storage. A hosted visual review workflow adds service setup and account requirements; check the provider’s current plan and terms for costs because they can change. The cited documentation establishes workflow capabilities, not a price comparison.
9. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. Its API can capture the before and after page images without setting up a browser locally. Save each response under a different filename, then compare the images with your preferred image-diff or review workflow. Keep the URL and capture options the same between requests. See the ScreenshotNeo API documentation.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await require('node:fs/promises').writeFile('shot.webp', image);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card required.
10. FAQ
Does a screenshot diff tell me whether the CMS update is correct?
No. It identifies visual changes relative to a baseline. Compare each difference with the intended edit and check content or behavior separately.
Should I update the baseline whenever the test fails?
No. Review the changed image first. Update the reference only when the new rendering is intentional and approved.
Should every pixel match exactly?
Exact matching is useful in a controlled environment. If known rendering variation remains, configure a small, justified threshold and continue reviewing meaningful changes.
Is a full-page capture enough to test responsive layouts?
No. It captures the whole page at one viewport. Capture and approve separate baselines for the viewport sizes you need to support.


