Visual regression testing catches the bugs that unit tests miss — broken layouts, CSS regressions, overlapping elements, and styling issues that only become visible in the rendered page. By comparing screenshots between deployments, you can detect unintended visual changes before they reach production.
How Visual Regression Testing Works
- Baseline capture — Take screenshots of key pages in your known-good state
- Comparison capture — Take the same screenshots after code changes
- Pixel diff — Compare the two sets and highlight differences
- Review — A human reviews the diff to approve or reject changes
Setting Up with a Screenshot API
While tools like Percy and Chromatic offer full-service visual testing, you can build a lightweight pipeline with a screenshot API and an image comparison library.
Step 1: Define Your Critical Pages
const pages = [
{ name: 'home', url: '/' },
{ name: 'pricing', url: '/pricing' },
{ name: 'docs', url: '/docs' },
{ name: 'dashboard-empty', url: '/dashboard' },
{ name: 'blog-listing', url: '/blog' },
];
Step 2: Capture Screenshots in CI
async function captureBaselines(baseUrl: string) {
for (const page of pages) {
const url = encodeURIComponent(baseUrl + page.url);
const res = await fetch(
`https://pxshot.dev/api/capture?url=${url}&width=1280&height=800&format=png&key=${API_KEY}`
);
const buffer = await res.arrayBuffer();
await fs.writeFile(`screenshots/${page.name}.png`, Buffer.from(buffer));
}
}
Step 3: Compare with Baselines
import pixelmatch from 'pixelmatch';
import { PNG } from 'pngjs';
function compareScreenshots(baseline: Buffer, current: Buffer): number {
const img1 = PNG.sync.read(baseline);
const img2 = PNG.sync.read(current);
const diff = new PNG({ width: img1.width, height: img1.height });
const mismatchedPixels = pixelmatch(
img1.data, img2.data, diff.data,
img1.width, img1.height,
{ threshold: 0.1 }
);
return mismatchedPixels / (img1.width * img1.height);
}
Step 4: Fail the Build on Unexpected Changes
const diffPercentage = compareScreenshots(baseline, current);
if (diffPercentage > 0.01) { // More than 1% pixel difference
console.error(`Visual regression detected: ${(diffPercentage * 100).toFixed(2)}% change`);
process.exit(1);
}
Best Practices
- Consistent viewport — Always use the same width and height
- Disable animations — Inject CSS to turn off transitions during capture
- Mock dynamic content — Replace dates, user-specific data, and ads with static content
- Multiple breakpoints — Test mobile (375px), tablet (768px), and desktop (1280px)
- Threshold tuning — Anti-aliasing differences are normal; set threshold to ~0.1
When to Run Visual Tests
- On every pull request (compare PR branch to main)
- Before major releases
- After dependency updates (especially CSS frameworks)
PxShot's API makes it easy to capture consistent screenshots across environments. See the API docs for all available parameters.