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

A Cypress screenshot comparison failure has two possible causes: the interface really changed, or the test captured a different state or rendering environment. Cypress’s cy.screenshot() command only creates an image; a plugin or hosted visual-testing service compares that image with a baseline. Start by inspecting the diff, then stabilize the capture conditions before approving any baseline.

This workflow separates genuine UI regressions from flaky screenshots and gives you concrete Cypress patterns for state, data, time, animation, viewport, browser, and snapshot-boundary problems.

1. Confirm what is actually failing

Read the comparison report before changing test code. Cypress itself does not compare pixels; its visual-testing guide describes integrations such as local image-diff plugins and hosted services. The failing layer may therefore be the capture, the comparison configuration, or the baseline-review workflow.

Classify the changed pixels

  • Layout or component geometry: a CSS, markup, breakpoint, or font change may be intentional or a real regression.
  • Text, colors, or icons: check deployed assets, feature flags, localization, and font loading.
  • Images or data: an API response, timestamp, random value, advertisement, or user-specific record may have changed.
  • Capture boundary: a full-page shot can include a footer, cookie notice, or lazy-loaded section unrelated to the component under test.
  • Scattered one-pixel noise: rendering differences from browser, operating system, display scaling, antialiasing, or missing fonts are more likely.

Do not approve a new baseline until you can explain the changed region and decide that the new appearance is intended.

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

2. Wait for the intended application state

cy.screenshot() is asynchronous. The page can continue changing between the command being queued and the actual capture, and it does not retry assertions chained after the screenshot. Put a meaningful assertion before the screenshot so Cypress waits for the state the image is meant to show.

cy.intercept('GET', '/api/orders', { fixture: 'orders.json' }).as('getOrders');
cy.visit('/orders');
cy.wait('@getOrders');
cy.get('[data-cy=orders-table]').should('be.visible');
cy.get('[data-cy=orders-table] tbody tr').should('have.length', 3);
cy.screenshot('orders-loaded');

The assertion should describe the visual contract: a heading contains the expected text, a spinner is absent, a menu has opened, or a table has the expected number of rows. An arbitrary cy.wait(2000) can hide a race on one machine and still be too short on another; use a condition tied to the UI instead.

Separate assertions from capture

Keep the state check as its own command chain. This makes a failed assertion explain why the page was not ready, rather than producing an ambiguous image mismatch.

cy.get('[data-cy=save-status]').should('contain', 'Saved');
cy.screenshot('profile-saved');

3. Make API data deterministic

Visual baselines require repeatable inputs. Stub changing endpoints with fixtures or explicit response bodies using cy.intercept(). Include stable IDs, ordering, and image URLs in the fixture; avoid production records whose contents can change between runs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.intercept('GET', '/api/dashboard*', {
  statusCode: 200,
  body: {
    updatedAt: '2026-01-15T10:00:00Z',
    users: [
      { id: 1, name: 'Ada Lovelace', status: 'Active' },
      { id: 2, name: 'Grace Hopper', status: 'Invited' }
    ]
  }
}).as('dashboard');

cy.visit('/dashboard');
cy.wait('@dashboard');
cy.get('[data-cy=dashboard]').should('be.visible');
cy.screenshot('dashboard');

If the application makes several requests, alias each one that affects the captured region and wait for all of them. Also control feature flags, authentication fixtures, locale, and seeded database state. A visual test that depends on “latest” content is testing the data feed as much as the UI.

4. Freeze clocks and other time-dependent values

Dates, countdowns, relative-time labels, rotating banners, and scheduled refreshes can produce different pixels on every run. Cypress can replace the browser clock with cy.clock(); install it before the application schedules timers.

cy.clock(new Date('2026-01-15T10:00:00Z').getTime());
cy.visit('/billing');
cy.get('[data-cy=invoice-date]').should('contain', 'Jan 15, 2026');
cy.screenshot('billing');

Advance the clock deliberately with cy.tick() when the scenario is about elapsed time. For random IDs or rotating content, inject a fixed seed or stub the generator at the application boundary. Do not freeze time globally if the test is intended to verify real-time behavior; isolate the deterministic setup to visual cases.

5. Stop animation and transient overlays

Animations can move an element between layout and capture. Cypress’s screenshot API documents disableTimersAndAnimations as enabled by default, but that capture setting does not disable every CSS animation, JavaScript animation loop, video, or transition already running on the page. The waitForAnimations and animationDistanceThreshold options govern actionability checks such as clicks, not unrelated page motion during a screenshot.

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.

Use a test-only animation reset

Inject a stylesheet or class that freezes transitions and animations for the visual test route:

cy.document().then((doc) => {
  const style = doc.createElement('style');
  style.textContent = `
    *, *::before, *::after {
      animation: none !important;
      transition: none !important;
      caret-color: transparent !important;
    }
  `;
  doc.head.appendChild(style);
});

cy.get('[data-cy=modal]').should('be.visible');
cy.screenshot('modal-open');

If a transition is part of the behavior being tested, wait for its final state instead of disabling it. Hide blinking carets, skeleton shimmer, autoplay video, and rotating carousels only when they are irrelevant to the visual assertion. A narrow selector mask or blackout provided by your comparison tool is safer than lowering a page-wide threshold.

6. Standardize viewport, browser, fonts, and operating system

Pixel comparisons are meaningful only when the renderer is comparable. Cypress documents a default viewport of 1000 × 660 pixels; that is a default, not a universal target. Set dimensions explicitly for the breakpoint you intend to verify.

describe('checkout visual states', () => {
  beforeEach(() => {
    cy.viewport(1280, 800);
    cy.visit('/checkout');
  });

  it('shows the shipping form', () => {
    cy.get('[data-cy=shipping-form]').should('be.visible');
    cy.screenshot('checkout-shipping');
  });
});

Generate and compare baselines in the same container or machine image. Pin the browser version where possible, install the exact web fonts used by the product, and keep device pixel ratio and display scaling consistent. A baseline made on macOS with a font unavailable in a Linux CI image is not a reliable reference. Cypress’s configuration documentation lists viewport and actionability defaults, including a 5-pixel animation-distance threshold; choose values for your test rather than assuming defaults are correct.

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.

Check font loading explicitly

cy.document().its('fonts.status').should('eq', 'loaded');
cy.get('[data-cy=hero-title]').should('be.visible');
cy.screenshot('hero');

For cross-platform comparisons, hosted visual systems may provide managed rendering, but verify the provider’s browser, font, data-retention, and review behavior before adopting it.

7. Narrow the snapshot boundary

Capture the smallest region that answers the test question. Cypress supports viewport, full-page, runner, and element capture modes through cy.screenshot() and the screenshot API. Full-page images are useful for page-level checks but also include more unrelated content and lazy-loaded sections.

cy.get('[data-cy=pricing-card]').screenshot('pro-plan-card');

Use a component or element shot when the failure is local. For a page-level requirement, capture full-page intentionally and make sure lazy images have loaded before the command. Comparison options such as masking, thresholds, and diff output belong to the plugin or service, not Cypress core; follow that integration’s current command syntax.

8. Decide whether to update the baseline

  1. Open the expected, actual, and diff images.
  2. Trace every changed region to a code, data, or environment change.
  3. For an intended design change, update the baseline using your plugin or service’s documented approval workflow and include the visual change in code review.
  4. For an intermittent mismatch, keep the baseline and fix nondeterminism first.
  5. For uncontrollable content, mask only the specific selector or region supported by your tool; do not relax the global threshold to make the report green.

Cypress retries are disabled by default. Enabling retries can demonstrate that a mismatch is flaky, but a passing retry does not prove that the new appearance is correct. Treat it as evidence for further diagnosis, not as a baseline-update strategy. See Cypress test retries.

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

9. Common failure symptoms and fixes

Symptom Likely cause Targeted fix
Only dates, timers, or “ minutes ago” text differ Real clock or refresh timer Install cy.clock(), stub time-sensitive responses, and assert the fixed value.
Rows or cards appear in a different order Uncontrolled API data or sorting Use a fixture with stable ordering and wait for the aliased request.
Diff shows a spinner, menu, or toast Capture occurred during a transition Assert the final state; disable irrelevant animation with test CSS.
Text wraps only in CI Viewport, font, browser, or device-scale mismatch Set viewport explicitly, pin the browser, install fonts, and compare in one image.
Large page diff after a small component edit Full-page boundary includes unrelated content Capture the element or component, or stabilize every included section.
Failure appears only occasionally Race, network, server, database, or resource dependency Use assertions and intercepts, inspect videos and logs, and reproduce in the same CI environment.
Screenshot file exists but no comparison result Capture layer is working; comparator is absent or misconfigured Check the plugin/service command, baseline path, and CI artifact configuration.

Cypress’s common error messages, screenshots and videos guide, and Cypress.Screenshot API help distinguish capture errors from test and comparison integration errors.

10. Choose a comparison workflow

Cypress identifies two broad approaches:

Consideration Local/open-source plugin Hosted visual service
Comparison Usually local pixel-by-pixel comparison Service-managed rendering and comparison vary by provider
Baselines Files stored and reviewed with the team Provider-managed baselines and approval workflow
Rendering Your team maintains matching environments Provider may manage render infrastructure
Review CI artifacts and pull requests Dashboard or pull-request review may be available
Cost and data Cypress characterizes open-source plugins as free, with images kept in team infrastructure Paid subscription category; verify current pricing and data handling
Coverage Configured browser and viewport per run Some services offer multiple browsers and viewport widths

Cypress names Cypress Image Diff, Cypress Image Snapshot, Cypress Visual Regression, Visual Regression Diff, Pixeleye, Applitools, Argos, Chromatic, and Sauce Labs Visual in its visual-testing material. Compare baseline ownership, browser coverage, environment consistency, review flow, data handling, price, and integration fit. Cypress does not provide the image-comparison layer itself.

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

Or skip the browser setup

If your goal is a clean reference image rather than an in-browser Cypress assertion, ScreenshotNeo returns a screenshot or PDF from one request. It accepts cookie and consent banners before capture, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and bills only clean shots. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; 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.

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(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo documentation for the complete parameter list. Relevant controls include full-page capture with lazy images, CSS-selector element capture, dark mode, 12 device presets or custom viewports, retina scale, custom CSS and JavaScript, click and wait conditions, blocked ads or resource types, headers, cookies, user agent, authorization, timezone, geolocation, transparent backgrounds, resizing, cache TTL, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, usage reporting, and an OpenAPI specification. Existing parameter names used by other screenshot APIs also work, which can simplify migration.

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

Plans include 1,000 screenshots per month free with no card, then Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing provides two months free, and every feature is on every plan. Create a free ScreenshotNeo account to start with the 1,000 monthly screenshots.

FAQ

Does Cypress compare screenshots by itself?

No. Cypress captures images; a plugin or external visual-testing service performs comparison, baseline management, and diff review.

Should I increase the diff threshold when a test fails?

Only after identifying harmless rendering noise and confirming the integration’s documented behavior. A global threshold can conceal a real layout or color regression; prefer deterministic rendering and narrow masks.

Why does a retry pass while the screenshot still fails sometimes?

The first run may have captured a race involving data, animation, network, or resources. A passing retry establishes intermittency, not correctness. Diagnose and remove the nondeterministic input.

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

When is a full-page screenshot appropriate?

Use it for an intentional page-level contract. For a component-specific check, an element screenshot produces a smaller, more actionable diff and avoids unrelated page changes.

Frequently Asked Questions

Does Cypress compare screenshots by itself?

No. Cypress captures images; a plugin or external visual-testing service performs comparison, baseline management, and diff review.

Should I increase the diff threshold when a test fails?

Only after identifying harmless rendering noise and confirming the integration’s documented behavior. A global threshold can conceal a real layout or color regression; prefer deterministic rendering and narrow masks.

Why does a retry pass while the screenshot still fails sometimes?

The first run may have captured a race involving data, animation, network, or resources. A passing retry establishes intermittency, not correctness. Diagnose and remove the nondeterministic input.

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

When is a full-page screenshot appropriate?

Use it for an intentional page-level contract. For a component-specific check, an element screenshot produces a smaller, more actionable diff and avoids unrelated page changes.

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.