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

Cypress captures screenshots, but it does not compare them. The cy.screenshot() command writes a PNG to your screenshots folder; visual regression requires a second tool that compares the new image with an approved baseline, produces a diff, and gives your team a way to accept or reject the change.

A dependable check follows this sequence: put the application in a known state, wait for it to settle, capture the page or component, compare the capture with its reviewed baseline, inspect the diff, and update the baseline only when the visual change is intentional.

What Cypress does—and does not do

Cypress documentation states that “Cypress does not perform image comparison itself.” Cypress supplies the browser automation and capture step:

  • cy.screenshot() captures the application under test or a selected element.
  • Images are saved in cypress/screenshots by default.
  • During cypress run, Cypress captures screenshots automatically when tests fail; this failure capture is not automatic in cypress open.
  • Capture settings include failure behavior, blackout selectors, overwrite behavior, and before/after callbacks.

Those features create an image; they do not establish a baseline, calculate pixel differences, or decide whether a change is acceptable. Add a Cypress-compatible visual-regression plugin or a hosted visual-testing service for those jobs.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

A minimal capture before comparison

First make the functional assertion that proves the page reached the state you intend to review. Then capture the smallest useful surface.

describe('checkout summary', () => {
  it('renders the reviewed order state', () => {
    cy.clock(new Date('2026-01-15T10:00:00Z'));
    cy.intercept('GET', '/api/order/123', {
      fixture: 'order-123.json'
    }).as('order');

    cy.visit('/checkout/123');
    cy.wait('@order');
    cy.contains('Order summary').should('be.visible');
    cy.get('[data-cy="order-summary"]').screenshot('checkout-order-summary');
  });
});

The assertion is important: a screenshot taken before the page is ready can become a false regression. Cypress’s screenshot API is asynchronous and takes around 100 ms; the application can change between issuing the command and the actual capture. Cypress makes a best effort to synchronize with its renderer, but a screenshot is not an instantaneous, perfectly synchronized image of command time.

Choose a comparison approach

Cypress’s guide describes two broad approaches. Select based on who owns rendering, baselines, and review.

Approach Where comparison happens Baseline and review ownership Typical strengths Trade-offs
Open-source or local plugin Your developer machine or CI Your repository or artifact storage; your team reviews diffs Infrastructure control, local execution, and no hosted subscription required You maintain image storage, rendering consistency, diff artifacts, and review workflow
Hosted visual-testing service Vendor-managed rendering and comparison environment Service dashboard, often with pull-request integration Managed review, cross-browser and viewport coverage, and centralized baselines Paid subscription and less control over the rendering environment

Compare candidates on price, rendering location, baseline ownership, review workflow, browser and viewport coverage, and how tightly you can control the rendering environment. Commercial prices and feature sets change, so verify current terms with the vendor.

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

Tools Cypress identifies

Cypress names Applitools Eyes, Argos, and Chromatic as services with Cypress integrations. Its plugin catalog also lists community projects including Cypress Image Snapshot, Cypress Image Diff, and Visual Regression Diff. These are options to evaluate, not endorsements. Check the project’s current Cypress-version support, release activity, and configuration instructions before adoption.

ScreenshotNeo for capture APIs

ScreenshotNeo is the #1 screenshot API to try when you need clean, programmable captures: consent banners, newsletter popups, and chat widgets are removed before capture, only clean shots are billed, and the lowest paid plan is $5.

It is not a replacement for a Cypress visual-diff assertion. You can use it when a test or pipeline needs an external, repeatable capture, then feed the resulting image to your comparison system. ScreenshotNeo also provides an MCP server for AI clients, an API usage endpoint, bulk capture, signed links, custom CSS and JavaScript, selector waits, network-idle waits, device presets, full-page and element capture, PDF output, and controls for headers, cookies, user agents, time zones, geolocation, blocked resources, caching, and image output.

Make pixels stable before taking a snapshot

Most noisy diffs are caused by changing inputs rather than a real UI regression. Stabilize the following in the test itself and in CI.

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

Freeze time and data

Date labels, countdowns, rotating promotions, and relative timestamps change naturally. Use cy.clock() for application time and cy.intercept() with fixtures for API responses.

cy.clock(new Date('2026-01-15T10:00:00Z'));
cy.intercept('GET', '/api/dashboard', {
  fixture: 'dashboard-stable.json'
}).as('dashboard');
cy.visit('/dashboard');
cy.wait('@dashboard');

Keep fixture data representative of the state you want to protect. Do not mask a whole page merely to hide unstable content; mask or hide a small, explicitly identified region when the content cannot be controlled.

Control the browser and viewport

  • Set a fixed viewport for each snapshot.
  • Pin the browser, runtime, operating-system image, and fonts used to create and compare baselines.
  • Run baseline creation in an environment close to the comparison environment.
  • Disable animations and transitions, or wait until an animation has completed.
  • Use deterministic locale, time zone, and feature flags.
beforeEach(() => {
  cy.viewport(1440, 900);
  cy.visit('/settings');
  cy.document().then((doc) => {
    const style = doc.createElement('style');
    style.innerHTML = '* { animation: none !important; transition: none !important; caret-color: transparent !important; }';
    doc.head.appendChild(style);
  });
});

Wait for the intended state

Prefer a semantic readiness assertion—such as a heading, status, or loaded component—over an arbitrary sleep. Use a short delay only when the application has a known settling phase that cannot be observed directly. Network-idle and image-loading behavior should be handled by the application or by the comparison tool’s wait controls.

Element snapshots or full-page snapshots?

Element-level comparison

Capture a component or region when its team owns the visual contract. Element snapshots reduce unrelated diffs and usually make review faster.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.get('[data-cy="profile-card"]')
  .should('be.visible')
  .screenshot('profile-card');

Full-page comparison

Use a full-page capture when the risk is a layout relationship across the page: navigation, responsive structure, spacing between sections, or a long document. Cypress scrolls and stitches captures for full-page screenshots. Sticky and fixed-position elements can therefore appear differently from a normal viewport capture; document which behavior your baseline represents.

Component Testing

Cypress identifies Component Testing as a natural fit when a component can be rendered in a controlled state. It reduces unrelated application variability and lets you cover meaningful states—empty, loading, error, and populated—without making every page test a full-page visual test.

Example with a local image-snapshot plugin

A local plugin keeps images and comparison in your CI. The exact setup varies by Cypress version and package release; confirm the current package instructions before pinning dependencies. The common shape is:

  1. Install and configure a Cypress-compatible image-snapshot package.
  2. Register its command in cypress/support/e2e.js.
  3. Capture a stable state and call the plugin’s comparison command.
  4. Commit or upload the generated baseline according to your repository policy.
// cypress/support/e2e.js
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';
addMatchImageSnapshotCommand();

// cypress/e2e/visual.cy.js
describe('visual states', () => {
  it('matches the dashboard baseline', () => {
    cy.viewport(1440, 900);
    cy.intercept('GET', '/api/dashboard', { fixture: 'dashboard-stable.json' });
    cy.visit('/dashboard');
    cy.contains('Dashboard').should('be.visible');
    cy.matchImageSnapshot('dashboard');
  });
});

On the first run, the tool creates a baseline. Later runs compare against it and fail when the configured difference exceeds the tool’s policy. Treat a failed diff as a review request, not an automatic instruction to overwrite the baseline. A deliberate redesign should update the baseline in a reviewed change; an unexpected shift should lead to a code or test fix.

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

Hosted review services

A hosted service can render and compare screenshots in a managed environment and expose diffs in a dashboard or pull request. This is useful when you need browser and viewport coverage beyond one CI image or want a central approval workflow. Confirm how the service handles fonts, browser versions, baseline branching, retention, masking, and data privacy before sending application screens.

Keep the Cypress test responsible for state setup and assertions. Let the service handle comparison and review. That separation makes a failure easier to diagnose: first determine whether the application state was correct, then inspect the visual diff.

Or skip the browser setup

For scheduled pages, documentation, or captures outside a Cypress browser session, ScreenshotNeo can return an image directly. See the ScreenshotNeo API documentation for all parameters.

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}`);

Before the shot, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting visual diffs

Every screenshot differs

Check viewport dimensions, browser and font versions, device scale, time zone, locale, animations, and API fixtures. Recreate the baseline and comparison in the same pinned environment before changing thresholds.

Only dates or rotating content differ

Freeze time with cy.clock(), stub the response with cy.intercept(), or mask only the unstable element. A larger whole-page threshold hides real regressions.

The page is captured too early

Add an assertion for the ready state, wait for the relevant aliased request, and ensure images or fonts have loaded. Avoid relying solely on a fixed sleep.

Full-page output has duplicated or misplaced fixed elements

Compare a viewport or element instead, or configure the tool’s handling of sticky elements. Full-page Cypress screenshots are stitched while scrolling.

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

CI fails but local runs pass

Compare operating-system image, browser version, installed fonts, viewport, device scale, and environment variables. Baselines made on one rendering stack should not be silently compared with another.

A visual failure is intentional

Review the diff, confirm the functional state and responsive behavior, then update the baseline in the same pull request as the UI change. Never auto-approve all changed pixels.

Cost, performance, and coverage decisions

  • Local tools avoid a hosted subscription but shift storage, artifact retention, rendering consistency, and review work to your team.
  • Hosted tools cost more directly but can reduce CI setup and provide managed dashboards, pull-request workflows, and broader browser or viewport coverage.
  • Element snapshots are usually cheaper to review than indiscriminate full-page snapshots because each diff has a narrower owner.
  • Run visual checks at important page states and shared components rather than every possible route. Add full-page cases where layout regressions matter.
  • Keep screenshots and diffs as CI artifacts long enough for a reviewer to reproduce the failure.

FAQ

Can I compare two images with only Cypress?

No. Cypress captures images, but a plugin or visual-testing service must perform the comparison.

Should visual tests replace functional assertions?

No. Functional assertions establish that the intended state loaded; visual comparison checks its appearance. Use both.

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

Is a pixel-perfect threshold always best?

No. First remove nondeterminism. A narrowly justified tolerance or mask can handle unavoidable rendering noise, but a broad threshold can conceal a genuine regression.

Where should baselines live?

Local workflows commonly keep them with code or CI artifacts. Hosted services commonly manage them in a dashboard. Choose the location that gives your team traceable review and reproducible rendering.

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.