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

Use @simonsmith/cypress-image-snapshot by wiring its Node event plugin into cypress.config.ts, registering its custom command in a Cypress support file, and calling cy.matchImageSnapshot() after the page reaches a stable visual state. The plugin compares each capture with a checked-in baseline, writes a diff when pixels differ, and (by default) fails the test. This guide covers installation, element and full-page captures, naming and paths, comparison controls, CI flags, reproducibility, compatibility checks, and failure diagnosis.

What the plugin does

The plugin adds visual regression assertions to Cypress. A test drives the application, Cypress captures the viewport or an element, and the plugin compares that image with a saved baseline. If the comparison differs, a diff image is written and the test fails unless you explicitly change that behavior.

Baselines and generated diffs stay in your project, so your team reviews image changes in the same code-review workflow as test changes. This is different from a hosted visual-testing service that stores captures and provides a remote review interface.

Check compatibility before installing

The package README says it was tested with Cypress 13.x and 14.x and that Cypress is a peer dependency. A current Cypress plugin-directory listing labels @simonsmith/cypress-image-snapshot@11.0.0 as requiring Cypress >=15.10.0. Those statements do not line up, and the requirement can vary by package release. Inspect the exact release metadata installed in your project instead of assuming either range applies universally.

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.
  1. Check your project’s Cypress version with npx cypress version.
  2. Check the package version and peer requirements with npm view @simonsmith/cypress-image-snapshot version peerDependencies (or inspect the installed package metadata).
  3. Resolve any peer-dependency warning before writing tests; a warning can become a command-registration or plugin-startup failure.

Install the development dependency

npm install --save-dev @simonsmith/cypress-image-snapshot
# or
yarn add --dev @simonsmith/cypress-image-snapshot

The package supplies TypeScript declarations. If TypeScript does not recognize matchImageSnapshot, include @simonsmith/cypress-image-snapshot/types in the project’s tsconfig.json type configuration.

Register both halves of the integration

Installation alone is not enough. The README’s setup has two independent registrations: a Node event plugin and a browser-side custom command.

1. Add the Node event plugin

In cypress.config.ts, call addMatchImageSnapshotPlugin(on) from setupNodeEvents:

import { defineConfig } from 'cypress'
import { addMatchImageSnapshotPlugin } from '@simonsmith/cypress-image-snapshot/plugin'

export default defineConfig({
  e2e: {
    setupNodeEvents(on) {
      addMatchImageSnapshotPlugin(on)
    },
  },
})

Keep your existing event handlers in the same function; add the call rather than replacing unrelated configuration.

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

2. Register the Cypress command

In the support file loaded by the relevant test type (for example, cypress/support/e2e.ts), register the command:

import { addMatchImageSnapshotCommand } from '@simonsmith/cypress-image-snapshot/command'

addMatchImageSnapshotCommand()

You can set defaults while registering the command. For example, this applies a shared failure threshold to every snapshot unless an individual call overrides it:

addMatchImageSnapshotCommand({ failureThreshold: 0.2 })

Capture a page or an element

Drive the UI to the state you want to protect, wait for content that affects the design, then call the command. With no argument, the snapshot name comes from the Cypress test title.

describe('login screen', () => {
  it('shows the validation state', () => {
    cy.visit('/login')
    cy.get('button[type="submit"]').click()
    cy.contains('Email is required').should('be.visible')
    cy.matchImageSnapshot()
  })
})

Use an explicit name when the test contains multiple visual states or when you want a stable, readable file name:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.matchImageSnapshot('login-validation')

A name can contain a nested path:

cy.matchImageSnapshot('auth/login/validation')

To capture one element instead of the viewport, start with a Cypress subject:

cy.get('#login').matchImageSnapshot()

Element snapshots are useful for components whose surrounding page changes frequently. Ensure the element has deterministic dimensions and is visible before capture.

Configure a snapshot call

The command accepts settings from the underlying jest-image-snapshot comparison layer together with Cypress screenshot settings. Common examples include:

cy.matchImageSnapshot('dashboard', {
  failureThreshold: 0.01,
  comparisonMethod: 'ssim',
  capture: 'viewport',
  blackout: ['.live-clock', '[data-testid="rotating-ad"]'],
})
  • failureThreshold: controls how much difference is tolerated. Choose a value deliberately and document why a non-zero tolerance is acceptable.
  • comparisonMethod: 'ssim': uses structural similarity rather than the default pixel comparison behavior.
  • capture: selects the Cypress capture mode, such as 'viewport'.
  • blackout: masks selectors whose changing content should not participate in the comparison.

Other options exposed by Cypress screenshots can be passed through the plugin. Confirm the option name against the installed release when upgrading, because Cypress and package versions can change supported settings.

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

Where baselines and diffs are written

The documented default layout is:

  • Baselines: <rootDir>/cypress/snapshots
  • Generated differences: <rootDir>/cypress/snapshots/__diff_output__

The first run creates a baseline when one does not already exist. Later runs compare against it. A mismatch produces a diff image for inspection. Commit accepted baseline files with the test so every checkout and CI job uses the same expected image.

Keep spec paths and snapshot paths aligned

For Cypress 10 and newer, common ancestor paths were removed from generated screenshots. The plugin’s e2eSpecDir option (default cypress/e2e/) preserves the intended relationship between spec files and snapshot directories. Set it to the directory represented by your specPattern when your project uses a different layout; otherwise snapshots can appear under surprising paths.

Update, require, or tolerate snapshots explicitly

Baseline changes should be a deliberate review operation, not an accidental side effect of a normal test run. The README documents different command-line syntax for newer and older Cypress releases.

Purpose Cypress 15.10+ Older Cypress versions
Update baseline images --expose updateSnapshots=true --env updateSnapshots=true
Do not fail on a visual diff --expose failOnSnapshotDiff=false --env failOnSnapshotDiff=false
Require pre-existing snapshots --expose requireSnapshots=true --env requireSnapshots=true

For example, a current Cypress run that intentionally refreshes baselines can be invoked as:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
npx cypress run --expose updateSnapshots=true

Use the update switch only while reviewing the resulting images. Inspect the baseline and any diff, then commit the accepted image together with the code change. In CI, requireSnapshots=true prevents a missing baseline from silently becoming a newly accepted one.

failOnSnapshotDiff=false is useful for an investigative run or a report-only job, but it removes the assertion’s protective failure. Keep the stricter default in the gate that blocks merges.

Make visual comparisons reproducible

Cypress’s visual-testing guidance recommends generating and comparing screenshots in the same environment with a fixed viewport. Rendering differences can otherwise look like product regressions.

Control the browser and viewport

beforeEach(() => {
  cy.viewport(1280, 800)
})

Run baseline creation and comparison with the same browser, operating-system image, fonts, device scale, viewport, and application build whenever possible.

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

Stabilize dynamic content

  • Wait for API-driven content and fonts before capturing.
  • Freeze clocks, random data, carousels, advertisements, and rotating promotions where your test framework permits.
  • Use blackout for intentionally volatile regions rather than accepting a broad threshold that could hide a real defect.
  • Capture after the final interaction, not immediately after cy.visit().

Review artifacts as code changes

Keep baseline images in version control, publish diff artifacts from CI, and require a reviewer to approve visual changes. A different rendering environment can create false positives even when application code is unchanged.

CI workflow that fails safely

  1. Install the locked dependency versions.
  2. Run Cypress in the same browser and viewport used to create baselines.
  3. Set requireSnapshots=true so missing files fail instead of creating expectations.
  4. Upload the Cypress screenshots and __diff_output__ artifacts when a job fails.
  5. Review a proposed UI change locally, run the update mode intentionally, and commit the reviewed baseline.

Do not combine baseline updating with the merge-blocking test command; that would allow a rendering change to rewrite the expected result during CI.

Troubleshooting common failures

“matchImageSnapshot is not a function”

The support file probably did not load, or the command registration import is missing. Verify the support-file path in Cypress configuration and add addMatchImageSnapshotCommand() there.

Plugin startup or peer-dependency errors

Check the installed package’s peer requirements against npx cypress version. The README’s tested versions and the directory listing’s requirement for 11.0.0 differ, so select a release whose metadata matches your project.

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

Every run reports a difference

Fix environment drift first: use the same viewport, browser, OS image, fonts, device scale, and application data. Then wait for late-loading images or fonts and mask genuinely dynamic selectors. Do not raise the threshold until you know the variation is harmless.

No baseline exists in CI

Check that snapshot files are committed and that the repository checkout includes them. Enable requireSnapshots=true to make this failure explicit.

Snapshots are in an unexpected directory

Compare e2eSpecDir with your specPattern and actual spec directory. The default assumes cypress/e2e/; custom layouts need a matching value.

You need a report without red builds

Run a separate report-only job with failOnSnapshotDiff=false. Keep the normal regression job at its default, fail-on-diff behavior.

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

Local plugin or hosted visual testing?

A local plugin keeps image comparison and storage in your repository or CI infrastructure. Your team controls baselines, rendering environments, retention, and review. Hosted services can centralize capture, storage, comparison, and review, and may provide consistent cloud rendering across browsers and viewport widths. Choose based on who owns image storage, how many browser and viewport combinations you need, the consistency you can maintain, and the review workflow your team will actually use. Current prices and commercial terms are not established here.

Or skip the browser setup

If your goal is an image of a URL rather than an assertion inside a Cypress test, ScreenshotNeo provides a single HTTP request and an MCP server for AI agents. It accepts consent banners before capture 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 response headers identify the page verdict and billing result.

Use the API documentation at https://screenshotneo.com/docs/ for all options. A minimal cURL capture is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in Python:

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 in 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 supports PNG, JPEG, WebP, and PDF output, full-page captures with lazy images loaded, CSS-selector element captures, device presets or custom viewports, dark mode, retina scale, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, an OpenAPI specification, and familiar parameter names for easier migration. Its MCP tools are take_screenshot, get_page_info, and capture_pdf.

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

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account to try it without a card.

Frequently Asked Questions

Does the plugin replace Cypress screenshots?

No. It uses Cypress’s screenshot capture and adds baseline comparison, diff generation, naming, and snapshot-specific controls.

Can I compare only part of a page?

Yes. Chain the command from a selector, such as cy.get('#login').matchImageSnapshot(), to compare that element rather than the viewport.

Should I commit the __diff_output__ directory?

Treat diff files as review artifacts. Commit accepted baselines; retain or publish diffs according to your CI artifact-retention policy.

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

Why does a clean machine produce different pixels?

Fonts, browser version, operating-system rendering, viewport, device scale, timing, and dynamic data can all change pixels. Keep generation and comparison in the same controlled environment.

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.