Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsPuppeteer captures screenshots; it does not decide whether two screenshots match. A reliable comparison workflow therefore has three layers: produce a deterministic render, capture the same viewport, page region, or element on every run, and pass the images to a separate diff tool or visual-testing service. Keep the approved baseline, current image, and diff artifact so a reviewer can distinguish an intentional design change from a regression.
What Puppeteer provides—and what it does not
Puppeteer’s Page.screenshot() captures a page and can write an image file or return image data. ElementHandle.screenshot() captures one selected element. Capture settings include full-page output, clipping, image type, output path, and transparent-background handling.
Comparison is a separate responsibility. Puppeteer does not provide a built-in baseline store, changed-pixel policy, failure threshold, diff report, or approval workflow. Add an image-diff library to your test harness, or use a hosted visual-testing service that stores baselines and review artifacts. Playwright Test’s screenshot assertion is a Playwright runner feature; it should not be described as a Puppeteer assertion.
The workflow in four repeatable stages
- Render a known state. Navigate to the exact URL, set the viewport and device scale factor, wait for the content that matters, and disable sources of random change such as animations or rotating data.
- Capture a baseline. Save a reference image using either
page.screenshot()or an element screenshot. Decide up front whether the contract is viewport-only, full-page, clipped, or element-level. - Capture the candidate. Run the same steps with the same browser build, operating system, fonts, viewport, and rendering mode.
- Compare and review. A diff tool reports changed pixels according to its policy. Publish the baseline, candidate, and diff together. A difference is a review signal, not automatic proof of a defect; update the baseline only as part of a deliberate code-review decision.
Set up a Node.js project
Install Puppeteer and an image-diff layer. The example below uses PNG decoding and pixel comparison so it can run as a normal Node.js script.
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 minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11#1 Best Overall
npm install puppeteer pngjs pixelmatch
Create a capture script that makes the rendering contract explicit:
const puppeteer = require('puppeteer');
const fs = require('node:fs');
async function capture(path) {
const browser = await puppeteer.launch({headless: true});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
await page.evaluate(() => {
const style = document.createElement('style');
style.textContent = '* { animation: none !important; transition: none !important; caret-color: transparent !important; }';
document.head.appendChild(style);
});
await page.screenshot({ path, type: 'png', fullPage: true });
} finally {
await browser.close();
}
}
capture(process.argv[2] || 'current.png').catch(error => {
console.error(error);
process.exit(1);
});
Generate an approved reference deliberately, rather than silently replacing it in every test:
node capture.js baseline.png
For a candidate run:
node capture.js current.png
Compare the baseline and candidate
The following script creates a red-highlighted diff and exits with status 1 when the changed-pixel count exceeds the policy you choose. The numeric tolerance is an example, not a universal recommendation; tune it only after stabilizing the environment.
const fs = require('node:fs');
const { PNG } = require('pngjs');
const pixelmatch = require('pixelmatch');
const baseline = PNG.sync.read(fs.readFileSync('baseline.png'));
const current = PNG.sync.read(fs.readFileSync('current.png'));
if (baseline.width !== current.width || baseline.height !== current.height) {
console.error(`Dimension mismatch: baseline ${baseline.width}x${baseline.height}, current ${current.width}x${current.height}`);
process.exit(2);
}
const diff = new PNG({ width: baseline.width, height: baseline.height });
const changed = pixelmatch(
baseline.data,
current.data,
diff.data,
baseline.width,
baseline.height,
{ threshold: 0.1, includeAA: false }
);
fs.writeFileSync('diff.png', PNG.sync.write(diff));
console.log(`Changed pixels: ${changed}`);
const allowed = 0;
process.exit(changed > allowed ? 1 : 0);
In a real project, make the policy part of test configuration: strict equality for highly controlled renders, or a documented changed-pixel allowance for known anti-aliasing variation. Keep the threshold and allowance with the test so a future maintainer can tell whether a failure reflects a policy change or a product change.
Recommended Free Tools
Rank #2
Choose the capture scope intentionally
| Scope | Puppeteer approach | Use it when | Main risk |
|---|---|---|---|
| Viewport | page.screenshot({fullPage:false}) |
The visible fold is the contract | Content below the fold is not checked |
| Full page | page.screenshot({fullPage:true}) |
Long documents, marketing pages, or complete layouts | Lazy content and page height can vary |
| Clipped region | page.screenshot({clip:{x,y,width,height}}) |
A stable panel or coordinate region matters | Layout shifts move the region |
| Element | const el=await page.$('.card'); await el.screenshot({path:'card.png'}) |
A component should be tested independently | Selector or element state may change |
Keep image type, viewport, clipping rectangle, and transparency settings identical for both images. Puppeteer documents PNG, JPEG, and WebP output; choose one format and keep it fixed for a comparison series. Use omitBackground:true only when transparent output is part of the contract.
Make rendering deterministic
Screenshot variation can come from the host operating system, browser version, browser settings, hardware, power source, headless mode, fonts, and the page itself. Generate and compare images in the same environment whenever possible.
- Pin the browser revision used by CI instead of allowing an unnoticed browser upgrade.
- Use a fixed viewport and device scale factor. A one-pixel dimension change can turn an otherwise identical page into a large diff.
- Install the same fonts in local and CI environments. Missing fonts alter wrapping, height, and glyph rasterization.
- Wait for a meaningful selector, not merely a fixed delay. A selector wait proves that the required content exists; a delay is useful only for a known animation or late resource.
- Freeze or mock clocks, random data, rotating carousels, ads, and user-specific content where your application permits it.
- Set a stable locale, timezone, color scheme, and authentication state so dates, currency, and responsive styles do not change between runs.
- Disable animations and transitions for regression captures, as in the example, and ensure video or canvas content has a deterministic frame.
Baseline storage and review policy
Store approved images with the code or in a dedicated artifact store that preserves version history. A useful failure bundle contains three files: the approved baseline, the candidate capture, and a visual diff. Include the URL, viewport, browser revision, commit identifier, and test name in the report.
Do not auto-approve every changed image. Reviewers should classify a change as intentional, environmental noise, or a regression. If intentional, update the baseline in the same change that modifies the UI. If environmental, fix the environment first; increasing tolerance can hide real defects.
Rank #3
Running in continuous integration
CI should execute the same capture command on every relevant change and fail when the comparison policy is exceeded. Publish the three image artifacts even on failure so a developer does not need to reproduce the run locally. Parallel captures are safe only when each test has an isolated page, output path, authentication state, and test data.
For large suites, reuse one browser process while creating separate pages, but close pages after each test. Avoid capturing every route at full-page size when a stable component screenshot answers the question; smaller images reduce storage and comparison time. A hosted visual-testing workflow can be useful when your team needs central baseline management and review rather than files managed in the repository.
Troubleshooting noisy or failed comparisons
The images have different dimensions
Check viewport width and height, device scale factor, full-page versus viewport mode, clipping coordinates, and responsive breakpoints. For full-page captures, inspect content that changes document height, including lazy-loaded images and fonts.
The page is blank or incomplete
Confirm the URL, authentication, network access, and browser console errors. Replace an arbitrary sleep with a wait for the selector that proves the page is ready. If the application requires network-idle waiting, use it consistently for both baseline and candidate runs.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #4
- Used Book in Good Condition
Text moves by a few pixels
Compare browser revision, operating system, installed fonts, headless mode, viewport, zoom, and device scale factor. Font fallback and anti-aliasing differences are environment problems before they are comparison-threshold problems.
Only dynamic widgets differ
Freeze test data, disable animations, hide or mock rotating content, and wait for the widget’s settled state. Do not broadly raise the tolerance until you know which pixels are legitimately variable.
An element screenshot fails
Verify the selector matches exactly one visible element, wait for it to be attached and rendered, and check that overlays or collapsed containers are not covering it. Capture the element after its final state is established.
The comparison passes but a visible defect remains
Inspect the diff policy. A large threshold or changed-pixel allowance can mask a real change. Use strict settings for critical UI and reserve allowances for measured, harmless rendering variation.
Best Value
Performance, reliability, and cost considerations
Full-page images are larger and slower to process than component captures. Reusing a browser process reduces launch overhead, while isolating pages prevents state leakage. Keep screenshots and diffs as CI artifacts for the retention period your team needs; large suites can otherwise consume substantial storage.
Puppeteer itself has no hosted-baseline fee in this workflow, but you are responsible for browser execution, CI minutes, artifact storage, and maintaining the comparison layer. A hosted service trades some infrastructure work for its own pricing and workflow. Select based on whether your priority is repository-controlled files or centralized review and baseline management.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server when you need a rendered image without maintaining a Puppeteer runtime. One GET request returns PNG, JPEG, WebP, or PDF output. The API accepts cleanup and rendering controls, including full-page capture with lazy images, CSS-selector element capture, device and viewport settings, custom CSS and JavaScript, waits, blocked requests, headers, cookies, user agents, timezone, geolocation, resizing, caching, signed links, asynchronous jobs, webhooks, and bulk capture of up to 100 URLs per call. See the ScreenshotNeo documentation for the current parameter names.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The equivalent Python request is:
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 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}`);
ScreenshotNeo accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets Claude, Cursor, or another MCP client call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try the API.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Frequently Asked Questions
Can Puppeteer compare PDFs directly?
Puppeteer’s screenshot APIs produce image captures. A PDF comparison requires a separate PDF-rendering or PDF-diff workflow; do not treat screenshot capture as a PDF assertion.
Should every visual difference fail CI?
Use a policy that matches the surface. Critical components may require zero changed pixels, while known rendering noise may justify a documented allowance. Always publish the diff for human review.
Is an element screenshot better than a full-page screenshot?
Neither is universally better. Element captures isolate a stable component; full-page captures cover page-level layout and interactions. Choose the smallest scope that proves the requirement.
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.

