Vitest visual regression testing runs in Browser Mode and compares a fresh browser capture with a committed reference image using toMatchScreenshot(). A reliable setup keeps visual tests in their own project, pins the browser and rendering environment, controls dynamic content, and requires a human review of every baseline change.
What Vitest visual regression testing does
Visual regression testing detects unintended changes to rendered pixels. Vitest launches a real browser through Browser Mode, captures the page or element you select, and compares that image with a reference stored beside the test. The first approved run creates the reference; later runs fail when the capture differs beyond your configured tolerance.
This complements, rather than replaces, behavioral tests. A screenshot can show that a Save button changed color or moved, but it cannot prove that clicking the button saves data. Keep interaction and state assertions in the same test or in your unit/component suite.
Prerequisites and provider choice
Install Browser Mode
Use Vitest’s interactive initializer:
npx vitest init browser
For a Playwright-backed setup, install the provider package:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →npm install -D @vitest/browser-playwright playwright
Vitest also documents WebdriverIO and preview providers. Headless execution requires Playwright or WebdriverIO; the preview provider is not a headless browser.
Choose a repeatable browser environment
- Pin Vitest, the browser provider, Playwright (or WebdriverIO), and the browser version.
- Generate and compare references on the same operating system and CI image.
- Keep GPU settings, installed fonts, screen scaling, headed/headless mode, and viewport dimensions consistent.
- Use a fixed viewport. Vitest’s example uses 1280 by 720; treat that as an example, not a universal requirement.
Separate visual tests from unit tests
Create a visual project with a naming convention such as **/*.vrt.test.[tj]s?(x), and exclude those files from the unit project. Separate projects let a pixel mismatch remain visible instead of being buried among behavioral failures.
import { defineConfig } from 'vitest/config'
import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
projects: [
{
name: 'unit',
include: ['src/**/*.{test,spec}.{js,ts,jsx,tsx}'],
exclude: ['**/*.vrt.test.{js,ts,jsx,tsx}'],
},
{
name: 'vrt',
include: ['src/**/*.vrt.test.{js,ts,jsx,tsx}'],
browser: {
enabled: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
headless: true,
viewport: { width: 1280, height: 720 },
},
},
],
},
})
Adjust the include patterns to your repository. The important properties are a distinct visual project, a browser provider, headless execution, and a fixed viewport.
Write a screenshot test in TypeScript
Render the component with your normal application test helper, locate the intended regression boundary, and call toMatchScreenshot().
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsimport { expect, test } from 'vitest'
import { page } from 'vitest/browser'
// Mount your component with the same helper used by other browser tests.
test('primary button looks correct', async () => {
const button = page.getByRole('button', { name: 'Save' })
// Keep functional checks separate from the visual assertion.
await expect(button).toBeVisible()
await expect(button).toMatchScreenshot('primary-save-button')
})
Use an element capture when the component is the boundary you own. A whole-page capture is useful for layout and routing regressions, but it also includes unrelated content, making failures noisier.
Create, review, and commit reference images
- Run the visual project for the first time. With no reference present, Vitest reports that a baseline must be created.
- Open the generated image and verify fonts, content, spacing, focus state, and responsive dimensions.
- Run the same project again. It now compares the new capture with the reference.
- Commit the approved reference files. Vitest stores them in
__screenshots__folders next to the tests.
References are source-controlled test artifacts. A baseline accepted without inspection can permanently encode a broken layout.
Run visual tests locally and in CI
Define separate scripts so developers can target either suite:
{
"scripts": {
"test:unit": "vitest --project unit",
"test:vrt": "vitest --project vrt"
}
}
CI should install the pinned browser and execute vitest --project vrt on the same image used to generate references. Do not regenerate baselines on a different operating system and expect pixel-identical output.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Control sources of unstable screenshots
Animations and transitions
Vitest’s built-in assertion disables animations by default with the Playwright provider. You can also load a setup stylesheet that sets animation and transition durations to zero. An endlessly moving page may never produce two consecutive matching captures and can time out.
Dynamic data
Mock timestamps, randomized identifiers, network responses, and user-specific content. With the Playwright provider, mask a changing region through the screenshot options when masking is preferable to mocking.
Fonts and rendering differences
Missing fonts, a changed browser build, GPU differences, operating-system text rendering, or a different device scale can produce diffs even when CSS did not change. Install the same fonts and use the same CI image for baseline creation and comparison.
Waiting for a stable page
Stable screenshot detection repeatedly captures until two consecutive captures match or the timeout is reached. Wait for the application’s loaded state or a meaningful selector before taking the screenshot instead of relying on an arbitrary short delay.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchConfigure comparison tolerance deliberately
Exact pixel equality is often too strict for anti-aliasing. Vitest supports comparator configuration, a per-pixel threshold, and allowedMismatchedPixelRatio. A ratio scales tolerance with image size, but there is no universal correct value. Start conservatively, review real failures, and document why your chosen tolerance is acceptable for the product.
Do not raise thresholds to make a failing build green without examining the image. A tolerance can hide a one-pixel border change, a shifted element, or a large low-contrast regression.
Diagnose a mismatch
- Open the expected reference, the actual capture, and the generated diff image.
- Determine whether the change is intentional (for example, an approved redesign) or environmental (font, browser, viewport, data, or animation).
- For anti-aliasing differences, check the comparator settings and rendering environment before changing application code.
- If dimensions differ, note that a diff image may not be generated; compare the two images directly and verify viewport and responsive breakpoints.
- Fix the cause, rerun the project, and review the result again.
Diff colors are diagnostic: Vitest’s guide describes red pixels as differences and yellow pixels as anti-aliasing differences when anti-aliasing is not ignored.
Rank #4
Update baselines safely
When a UI change is intentional, run the visual project with --update, inspect every changed image, and commit the approved references together with the code change.
vitest --project vrt --update
Never treat the ability to update as approval. Review the resulting files in code review. Screenshots for deleted or renamed tests are not automatically removed, so delete stale references during test cleanup.
Common failures and fixes
“No browser provider” or browser launch errors
Cause: Browser Mode is enabled without a supported provider or the browser is not installed. Fix: install @vitest/browser-playwright and Playwright, run the provider’s browser installation step in your project, and verify the visual project configuration.
Every run reports differences
Cause: mismatched OS, browser, fonts, viewport, GPU, scale factor, or headed/headless mode. Fix: pin versions and run both baseline generation and CI comparisons on one image.
The test times out waiting for stability
Cause: an animation, carousel, clock, or continuously changing network response. Fix: disable motion, mock the data, wait for a stable selector, or mask the dynamic region.
Best Value
Only the first run fails because no reference exists
That is expected. Inspect the generated image, then commit it as the approved baseline and rerun.
A redesign created hundreds of failures
Confirm the redesign is intentional, update only the affected references with --update, and inspect the complete diff. Do not change a global tolerance to bypass review.
Performance, reliability, and maintenance
- Capture the smallest meaningful element to reduce rendering work and unrelated failures.
- Run unit and visual projects independently so a slow browser suite does not obscure fast feedback.
- Keep test data deterministic and avoid live third-party content.
- Use one pinned CI image for all visual jobs; parallelize only when each worker has the same browser and font environment.
- Review reference files when tests are renamed, removed, or moved, because old images can remain behind.
Or skip the browser setup
If you need an image of a deployed page rather than a repository-controlled Vitest baseline, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled.
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are free, and response headers report the page verdict and whether the request was billed. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
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)
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}`);
See the ScreenshotNeo documentation for the full option set, including full-page and selector captures, device presets, retina scale, dark mode, custom CSS and JavaScript, clicks, waits, blocked requests, headers, cookies, user agents, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture, usage data, and the OpenAPI specification.
The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account.
Frequently asked questions
Does a screenshot test replace accessibility testing?
No. It can reveal visible regressions, but it does not replace semantic, keyboard, or assistive-technology checks.
Should baselines be stored in Git?
Yes, commit reviewed references next to the tests so changes are versioned with the code that produced them.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
When should I capture a whole page?
Use whole-page captures for page-level layout contracts. Prefer an element capture when the intended contract is a specific component.
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.

