What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Puppeteer can capture a webpage or a selected element, but capturing an image is only the first half of screenshot testing. To test for visual regressions, compare each new capture with a reviewed reference image under repeatable browser, viewport, and page-state conditions. Then inspect any differences before deciding whether to fix the page or approve a new baseline.

Screenshot capture and screenshot testing are different steps

Puppeteer’s Page.screenshot() captures a rendered page and returns image data. Its screenshots guide also shows capturing a particular element with ElementHandle.screenshot(). Neither capture tells you whether the result is correct.

A visual regression test adds a reference image—the approved appearance—to the workflow. It captures the page again, compares the current image with that reference, and presents differences for review. Image comparison is separate from Puppeteer’s capture API: you supply a comparison tool or build that step into your test setup. Jest’s documentation distinguishes this image-based visual regression from serialized snapshots, which compare text-like representations of values: Jest snapshot testing.

Use image checks for rendered appearance, such as layout, spacing, and styling. Add DOM or functional assertions when you need to verify text, accessible names, URLs, state, or interactions. A matching screenshot cannot prove that a control works or that semantic content is correct.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Capture a page in Puppeteer

Start with an explicit URL, viewport, and readiness condition. The following CommonJS script uses Puppeteer’s documented page screenshot API and writes a PNG to disk:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1365, height: 900, deviceScaleFactor: 1 });
    await page.goto('http://localhost:3000', { waitUntil: 'networkidle2' });
    await page.screenshot({ path: 'homepage.png', fullPage: true });
  } finally {
    await browser.close();
  }
})();

Install Puppeteer in the project before running the script, and use a URL that your test process can reach. The Puppeteer API reference supplied here is labeled version 25.12.0; options and behavior can change, so check the API documentation matching the version installed in your project.

networkidle2 is a useful example condition, not a guarantee that every image, font, animation, or client-side component has finished rendering. If the page has a known readiness signal, wait for that instead—for example, a selector that appears when the relevant content is ready. Set the condition to match the page, rather than relying on elapsed time alone.

Choose the right capture scope

Capture a full page for broad layout checks

Use fullPage: true when the test concerns the overall page, including content below the initial viewport. This can reveal page-level layout shifts, missing sections, and styling changes outside the first screen. Long pages produce larger images and can make a diff harder to interpret, so use a focused component capture when the whole page is not relevant.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Capture an element to isolate a component

When the question is whether a specific card, navigation bar, or other component still renders as expected, locate it and capture its element handle:

const element = await page.waitForSelector('[data-testid="pricing-card"]');
if (!element) throw new Error('Pricing card was not found');
await element.screenshot({ path: 'pricing-card.png' });

Puppeteer’s guide notes that an element hidden offscreen is scrolled into view by default when captured. That is convenient, but it means the page may move as part of the capture. Choose a stable selector that identifies the intended element, and make sure the element is present and visible in the state your test is meant to cover.

Add a comparison and review the diff

Puppeteer produces the image; your test workflow must decide how to compare it with a baseline. Select an image-diff library or a test framework that fits your project, store reference images with the test code or in an intentionally managed artifact store, and make the comparison result visible to reviewers. Keep access to the current image, the approved reference, and a diff visualization so a failure is diagnosable rather than just a pass/fail number.

  1. Capture under known conditions. Use fixed input data, a defined viewport, a consistent browser environment, and a deliberate readiness condition.
  2. Compare current output with the approved reference. Configure your chosen image-comparison step to report differences according to the tolerance appropriate to your app and renderer.
  3. Inspect the artifacts. Review the current image, reference, and diff. Decide whether the change indicates a regression, an intended design update, or rendering noise.
  4. Update a baseline only after review. Record why an accepted appearance changed and commit or otherwise version the new reference with the change it represents.

Jest recommends committing snapshots alongside code and reviewing changes in code review; it also cautions against regenerating snapshots simply because a test failed. The same review discipline is useful for image baselines. Playwright documents an explicit snapshot update command, but that command is for Playwright’s own visual testing workflow, not a Puppeteer API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make captures repeatable

Visual comparisons are only useful when the environment and page state are sufficiently consistent. Playwright’s visual comparison guidance explains that rendering can vary with the host operating system, browser version, settings, hardware, power conditions, and headless mode: Playwright visual comparisons. Keep the baseline environment and test environment alike wherever practical.

  • Pin the rendering setup. Use the same browser family and version, operating system, viewport dimensions, device scale factor, and font availability for baseline creation and routine runs.
  • Use deterministic page data. Fix dates, random values, user records, and other test inputs so unchanged inputs produce unchanged output. Jest identifies platform-specific or nondeterministic data as a source of snapshot mismatch.
  • Wait for the right state. Prefer an application-ready selector or another explicit page signal when available. Network idleness can be insufficient for lazy images, delayed widgets, or client-side work.
  • Control motion and changing content. Disable or settle animations deliberately, and avoid or stabilize timestamps, rotating banners, live counters, and other volatile regions.
  • Avoid accidental pointer states. Move the mouse away from interactive controls if hover styling is not part of the test. Playwright offers screenshot-specific controls for volatile regions; Puppeteer users should implement equivalent setup deliberately rather than assume those Playwright APIs exist in Puppeteer.

These controls do not mean that every pixel must always be identical across every machine. They reduce avoidable variation so a reported difference is more likely to help identify a meaningful change.

Interpret failures without accepting regressions blindly

A diff can represent a real defect, a deliberate design change, or a mismatch in test conditions. First verify that the same data, viewport, browser environment, fonts, and readiness state were used. Then inspect whether the difference is localized or broad: a component-only capture can help isolate an issue that is hard to read in a very long page image.

  • Unexpected layout or style change: inspect the page and its recent code or data changes; fix the implementation if the rendered result is unintended.
  • Difference only on one machine or run: check environment consistency and volatile content before changing the baseline.
  • Intentional redesign: review the new appearance, update the reference through the project’s normal review process, and document the reason for the change.
  • Unclear result: open the actual, baseline, and diff images and narrow the capture to the relevant page region or component.

Do not make automatic baseline replacement the default failure response. It can turn an actual regression into a newly approved reference without anyone noticing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Know what a screenshot test cannot establish

Image-based checks answer whether the rendered pixels differ from an accepted image. They can catch visible shifts in layout, styling, and rendering, but they do not establish that hidden behavior works, that a link points to the right destination, or that a control has the intended accessible name. Pair screenshots with assertions for the page URL, important text, DOM state, accessibility properties, and user interactions where those requirements matter.

Do not confuse image comparisons with serialized snapshot tests. Jest describes visual regression as comparing webpage screenshots, often pixel by pixel; ordinary snapshot testing serializes values and compares text artifacts. Both can be useful, but they test different outputs.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common Puppeteer screenshot-test failures

The capture is blank or incomplete

Check that navigation reached the intended page and that the capture waits for the content your test needs. A navigation event such as networkidle2 is not proof that every lazy-loaded or asynchronously rendered asset is ready. Wait for an application-specific selector or state, and verify the URL and expected DOM content before capturing.

The image differs on every run

Look for changing data, animation, timestamps, rotating content, hover state, or inconsistent fonts. Then confirm that repeated runs use the same browser version, platform, viewport, device scale, and page inputs. Stabilize the source of variation before adjusting the image comparison tolerance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An element capture fails to find its target

Verify the selector against the rendered DOM, wait for it to appear, and fail with a clear error if it is absent. If the element is conditionally rendered, set up the state that makes it appear before the capture rather than substituting an unrelated selector.

A diff is hard to review

Provide reviewers with the reference, actual image, and a visual diff. Reduce the capture scope to a relevant component when a long full-page image obscures the change, and keep test conditions fixed so reviewers are not sorting through unrelated noise.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request can return a PNG, JPEG, WebP, or PDF; for screenshot testing, treat the returned image as a capture and still compare it against your reviewed reference. The API provides page-verdict and billing headers, so failed loads and other non-clean outcomes can be distinguished from billable clean captures. See the 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

Cookie and consent banners are accepted and removed before capture; the service also removes known consent platforms, newsletter popups, and chat widgets, with each cleanup step configurable. Bot checks, blank pages, timeouts, and failed loads are not billed, and cache hits cost nothing. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.

Frequently Asked Questions

Does Puppeteer include a built-in visual image-diff assertion?

No. Puppeteer captures images; comparison with a reference is a separate step that you add to your test workflow.

Can I use Playwright’s toHaveScreenshot() in a Puppeteer test?

No. Playwright documents that its screenshot assertion works with the Playwright test runner; it is not a Puppeteer feature.

Should I replace a baseline whenever a screenshot test fails?

No. Inspect the current image, reference, and diff first, then update the baseline only when the changed appearance is intended and reviewed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.