Use Case Guide ยท Updated February 2026
Design QA: Automated Visual Regression Testing
A CSS change breaks the header on mobile. A font update shifts the checkout button off-screen. A dependency upgrade subtly changes spacing across 50 pages. These are the bugs that unit tests don't catch and manual QA misses. Visual regression testing catches them all โ automatically.
SnapAPI lets you capture screenshots of your UI across multiple viewports and devices, then compare them against baseline images to detect any visual change โ no matter how small.
๐จ Catch UI Bugs Before Your Users Do
Multi-viewport screenshots for visual regression testing. 200 free captures/month.
Get Free API Key โThe Problem: CSS Breaks Are Silent
Traditional testing catches logic errors โ broken API calls, wrong calculations, missing data. But visual bugs are different:
- No error is thrown โ the page loads fine, it just looks wrong
- Hard to test in code โ you can't easily assert that "the button is in the right place"
- Device-specific โ a layout that works on desktop may break on mobile or tablet
- Cumulative โ small changes compound over time until the UI drifts far from the design
- Costly to find manually โ QA engineers clicking through every page after every deploy
Visual regression testing solves this by taking a screenshot of each page/component, comparing it to a known-good baseline, and flagging any pixel differences. Add it to your CI/CD pipeline and you'll catch visual bugs before they reach production.
Build Visual Regression Tests with SnapAPI
Capture Multiple Viewports
# Desktop
curl "https://api.snapapi.pics/v1/screenshot?url=https://staging.yourapp.com/checkout&width=1440&height=900&format=png" \
-H "Authorization: Bearer YOUR_API_KEY" -o checkout-desktop.png
# Tablet
curl "https://api.snapapi.pics/v1/screenshot?url=https://staging.yourapp.com/checkout&width=768&height=1024&format=png" \
-H "Authorization: Bearer YOUR_API_KEY" -o checkout-tablet.png
# Mobile
curl "https://api.snapapi.pics/v1/screenshot?url=https://staging.yourapp.com/checkout&width=375&height=812&format=png" \
-H "Authorization: Bearer YOUR_API_KEY" -o checkout-mobile.png
Python: CI/CD Visual Regression Pipeline
import requests
from PIL import Image
import numpy as np
import sys
SNAPAPI_KEY = "YOUR_API_KEY"
BASE = "https://api.snapapi.pics/v1"
HEADERS = {"Authorization": f"Bearer {SNAPAPI_KEY}"}
VIEWPORTS = [
{"name": "desktop", "width": 1440, "height": 900},
{"name": "tablet", "width": 768, "height": 1024},
{"name": "mobile", "width": 375, "height": 812},
]
PAGES = ["/", "/pricing", "/checkout", "/dashboard", "/settings"]
def capture_page(base_url, path, viewport):
"""Capture a single page at a specific viewport."""
resp = requests.get(f"{BASE}/screenshot", params={
"url": f"{base_url}{path}",
"width": viewport["width"],
"height": viewport["height"],
"format": "png",
"full_page": "true"
}, headers=HEADERS)
return resp.content
def compare_images(baseline_path, current_bytes, threshold=0.1):
"""Compare two images, return diff percentage."""
baseline = np.array(Image.open(baseline_path))
current = np.array(Image.open(io.BytesIO(current_bytes)))
if baseline.shape != current.shape:
return 100.0 # Different dimensions = total mismatch
diff = np.abs(baseline.astype(float) - current.astype(float))
changed_pixels = np.sum(diff > 10) / diff.size * 100
return changed_pixels
def run_visual_tests(staging_url, baseline_dir="baselines"):
"""Run visual regression tests against all pages and viewports."""
failures = []
for page in PAGES:
for vp in VIEWPORTS:
print(f"Testing {page} @ {vp['name']}...", end=" ")
screenshot = capture_page(staging_url, page, vp)
baseline = f"{baseline_dir}{page.replace('/', '_')}_{vp['name']}.png"
try:
diff_pct = compare_images(baseline, screenshot)
if diff_pct > 0.1:
failures.append(f"{page} @ {vp['name']}: {diff_pct:.2f}% changed")
print(f"FAIL ({diff_pct:.2f}% diff)")
else:
print("PASS")
except FileNotFoundError:
# No baseline yet โ save this as the new baseline
with open(baseline, "wb") as f:
f.write(screenshot)
print("NEW BASELINE")
if failures:
print(f"\nโ {len(failures)} visual regression(s) detected:")
for f in failures:
print(f" - {f}")
sys.exit(1)
else:
print("\nโ
All visual tests passed!")
run_visual_tests("https://staging.yourapp.com")
Node.js: GitHub Actions Integration
const API_KEY = process.env.SNAPAPI_KEY;
const BASE = 'https://api.snapapi.pics/v1';
const { PNG } = require('pngjs');
const pixelmatch = require('pixelmatch');
const fs = require('fs');
async function captureScreenshot(url, width, height) {
const res = await fetch(
`${BASE}/screenshot?url=${encodeURIComponent(url)}&width=${width}&height=${height}&format=png&full_page=true`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
return Buffer.from(await res.arrayBuffer());
}
async function visualDiff(pageUrl, viewportName, width, height) {
const current = await captureScreenshot(pageUrl, width, height);
const baselinePath = `baselines/${viewportName}.png`;
if (!fs.existsSync(baselinePath)) {
fs.writeFileSync(baselinePath, current);
return { status: 'new_baseline' };
}
const baseline = PNG.sync.read(fs.readFileSync(baselinePath));
const currentPng = PNG.sync.read(current);
const { width: w, height: h } = baseline;
const diff = new PNG({ width: w, height: h });
const mismatchedPixels = pixelmatch(
baseline.data, currentPng.data, diff.data, w, h,
{ threshold: 0.1 }
);
const diffPercent = (mismatchedPixels / (w * h)) * 100;
if (diffPercent > 0.1) {
fs.writeFileSync(`diffs/${viewportName}-diff.png`, PNG.sync.write(diff));
return { status: 'failed', diffPercent, mismatchedPixels };
}
return { status: 'passed', diffPercent };
}
// Use in CI: node visual-test.js https://staging.yourapp.com
const stagingUrl = process.argv[2];
const results = await visualDiff(stagingUrl, 'homepage-desktop', 1440, 900);
console.log(results);
Why SnapAPI for Visual Testing
| Aspect | Local Playwright/Puppeteer | SnapAPI |
|---|---|---|
| CI/CD setup | Install Chrome, configure Xvfb, manage deps | One HTTP call, no browser to install |
| Cross-platform consistency | Renders differ between CI and local | Consistent rendering environment |
| Font rendering | Missing fonts in CI = different screenshots | Full font stack pre-installed |
| Viewport testing | Need to configure each device | Set width/height per request |
| Full-page capture | Complex scrolling logic | full_page=true parameter |
| CI minutes | ~30s per page (browser startup) | ~3s per page (API call) |
Key Benefits
๐ Fast CI Integration
No browser installation in CI. Just HTTP calls. Cuts visual test pipeline time by 80% compared to local Puppeteer.
๐ฑ Multi-Device Coverage
Test desktop, tablet, and mobile viewports with a single API. Catch responsive layout bugs across all breakpoints.
๐ฏ Pixel-Perfect Consistency
Same rendering environment every time. No more "works on my machine" screenshot mismatches between local and CI.
๐ธ Full-Page Capture
Capture entire scrollable pages, not just the viewport. Detect regressions in footers, below-the-fold content, and long forms.
Design QA Workflow
- Generate baselines โ capture screenshots of your approved UI and save them as reference images
- Run on every PR โ capture the same pages on your staging/preview environment
- Compare pixel-by-pixel โ use libraries like
pixelmatchorPillowto detect differences - Fail the build โ if visual diff exceeds your threshold, block the merge
- Update baselines โ when intentional changes are approved, update the reference images
Add Visual Testing to Your CI/CD Pipeline
Multi-viewport screenshots with consistent rendering. No browser infrastructure to manage.
Get Free API Key โFAQ
How consistent are screenshots between captures?
SnapAPI uses a standardized Chromium environment with fixed font rendering and deterministic page load. For the same URL and viewport, screenshots are pixel-identical when the page content hasn't changed.
Can I test pages behind authentication?
Yes. Pass cookies or session headers via the API to capture authenticated pages. Perfect for testing dashboards, admin panels, and user-specific views.
What image comparison library should I use?
For Node.js, pixelmatch is the standard. For Python, use Pillow with NumPy. Both work well with PNG screenshots from SnapAPI.
Can I capture specific components instead of full pages?
Use the selector parameter to capture a specific CSS selector. For example, selector=.checkout-form captures just the checkout form element.
Related: Visual Regression Testing ยท Social Media Cards ยท Free Screenshot API Guide ยท API Documentation