Visual Regression Testing

Visual Regression Testing
Without the Setup

Screenshot any URL via API — before and after every deploy. Pipe the images into your existing diff tool. No browser to configure, no flaky screenshot infrastructure to maintain.

100 calls/month free · No credit card · Works in any CI/CD pipeline

Why screenshot-based visual testing breaks in CI

The tooling works locally. Production is a different story.

Flaky Puppeteer screenshot tests

Font rendering, animation timing, and subpixel differences vary between OS and GPU — so screenshots taken on macOS don't match CI Linux. Tests fail randomly.

Browser version mismatches

The Chrome version on your CI runner is different from local. Screenshots differ by 1–3% even on identical pages. Threshold tuning becomes a full-time job.

Infrastructure overhead

Running Chromium in CI means system library dependencies, sandbox flags, memory limits, and 300MB+ downloads per fresh runner. Complex for zero business value.

How it works with SnapAPI

SnapAPI provides consistent, reproducible screenshots from the same infrastructure every time.

Before deploy

Capture baseline

Call the screenshot endpoint for each critical page. Save the PNG files as the visual baseline.

After deploy

Capture current

Call the same endpoint again after the deploy completes. Same URL, same dimensions, same API.

Compare

Pixel diff

Use any pixel-diff library (pixelmatch, resemblejs, or a SaaS like Percy) to compare. SnapAPI just provides the screenshots.

CI/CD workflow example

The core pattern — swap in any diff library.

// visual-regression.js — run before/after deploys in CI
// npm install snapapi-sdk pixelmatch pngjs
const snap      = require('snapapi-sdk');
const pixelmatch = require('pixelmatch');
const { PNG }    = require('pngjs');
const fs         = require('fs');

const api = new snap.SnapAPI(process.env.SNAPAPI_KEY);
const PAGES = ['https://myapp.com', 'https://myapp.com/pricing'];

async function captureBaseline() {
  for (const url of PAGES) {
    const slug = new URL(url).pathname.replace(/\//g, '-') || 'home';
    const buf = await api.screenshot({ url, width: 1280, height: 800, format: 'png' });
    fs.writeFileSync(`baseline${slug}.png`, buf);
  }
}

async function compareWithBaseline() {
  let failed = false;
  for (const url of PAGES) {
    const slug     = new URL(url).pathname.replace(/\//g, '-') || 'home';
    const current  = PNG.sync.read(await api.screenshot({ url, width: 1280, height: 800 }));
    const baseline = PNG.sync.read(fs.readFileSync(`baseline${slug}.png`));
    const diff     = new PNG({ width: current.width, height: current.height });
    const changed  = pixelmatch(baseline.data, current.data, diff.data, current.width, current.height, { threshold: 0.1 });
    const pct      = (changed / (current.width * current.height) * 100).toFixed(2);
    if (changed > 100) { // more than 100 pixels different
      console.error(`FAIL ${url} — ${pct}% changed (${changed} pixels)`);
      fs.writeFileSync(`diff${slug}.png`, PNG.sync.write(diff));
      failed = true;
    } else {
      console.log(`OK   ${url} — ${pct}% changed`);
    }
  }
  if (failed) process.exit(1); // fail CI step
}

// Run: CAPTURE=1 for baseline, nothing for comparison
process.env.CAPTURE ? captureBaseline() : compareWithBaseline();

SnapAPI always runs the same Chromium version on consistent infrastructure — no per-runner variation, no subpixel drift between OS environments.

Compatible with your existing tools

SnapAPI provides the screenshots. You use whatever diff tool you already have.

pixelmatchFast pixel-diff npm package
resemblejsImage analysis and comparison
PercySaaS visual review platform
ApplitoolsAI-powered visual testing
BackstopJSVisual regression framework
Any image diff librarySnapAPI outputs standard PNG

Add visual regression to your pipeline today

Free API key — 100 calls/month, works in any CI environment.

Get Free API Key →