Use Image Diff Viewer

Enter your data below to use the Image Diff Viewer

📌 Try these examples:
RESULT

Last updated

Visual Regression Testing

The Image Diff Viewer compares two images and highlights pixel-level differences. Here is how it is used in visual regression testing:

/* Comparison modes */

Side-by-side mode:
  [Before Image] | [After Image]
  Best for: Obvious layout changes, color changes
  Use when: You want to see both versions simultaneously

Overlay mode (adjustable opacity):
  [Before at 50% opacity] overlaid on [After at 50% opacity]
  Best for: Checking alignment, subtle position shifts
  Use when: Elements may have moved slightly

Difference mode:
  [Highlighted diff image — only changed pixels shown]
  Red pixels:    Present in Before, removed in After
  Green pixels:  Added in After, not in Before
  Yellow pixels: Changed color between versions
  Best for: Finding exact location of all changes

Slider mode:
  [Before ←→ After] with draggable divider
  Best for: Before/after comparisons, design reviews
  Use when: Showing stakeholders what changed

/* Difference statistics */
Total pixels:      1,920,000  (1920×1000px)
Changed pixels:    4,832
Percentage changed: 0.25%
Average color diff: 12.4 (out of 255)
Status: Minor changes detected

UI Screenshot Comparison

Comparing before and after a CSS change to verify only intended elements changed:

/* Scenario: Updated button color from blue to green */

Before screenshot: homepage-v1.png
After screenshot:  homepage-v2.png

/* Expected diff */
Changed regions:
  - Primary CTA button: rgb(26,115,232) → rgb(52,168,83)
  - Hover state button: rgb(21,94,190) → rgb(41,134,66)
  - Active state button: rgb(16,73,148) → rgb(30,100,50)

/* Unexpected diff (regression found!) */
Changed regions:
  - Navigation link color: rgb(26,115,232) → rgb(52,168,83)
    ⚠ Navigation links also changed — unintended side effect!
    Root cause: CSS selector was too broad (.btn → a)

/* Diff statistics */
Expected changed pixels:  1,240  (buttons only)
Actual changed pixels:    3,890  (buttons + nav links)
Regression detected:      Yes — 2,650 unexpected pixel changes

/* Fix: narrow the CSS selector */
/* Before: */
a { color: #34a853; }

/* After: */
.btn-primary { color: #34a853; }

Design Mockup vs Implementation Comparison

Comparing a Figma design export with a browser screenshot to find discrepancies:

/* Design handoff verification */

Image A: figma-design-export.png  (designer's mockup)
Image B: browser-screenshot.png  (developer's implementation)

/* Common discrepancies found by diff viewer */

Typography:
  Font weight: 600 (design) vs 500 (implementation)
  → Diff shows slightly different text rendering
  Fix: font-weight: 600 in CSS

Spacing:
  Padding: 24px (design) vs 20px (implementation)
  → Diff shows elements shifted by 4px
  Fix: padding: 24px in CSS

Colors:
  Background: #F8F9FA (design) vs #F5F5F5 (implementation)
  → Diff shows subtle color difference
  Fix: background-color: #F8F9FA

Border radius:
  Radius: 12px (design) vs 8px (implementation)
  → Diff shows slightly different corner curves
  Fix: border-radius: 12px

/* Diff report */
Total discrepancies: 4
Critical (layout shifts): 1
Minor (color/style): 3
Pixel-perfect match: No
Recommendation: Fix padding issue first (affects layout)

Automated Visual Testing Pipeline

Integrating image comparison into CI/CD for automated visual regression detection:

/* Using Playwright for screenshot capture + comparison */
const { test, expect } = require('@playwright/test');

test('homepage visual regression', async ({ page }) => {
  await page.goto('https://example.com');
  await page.waitForLoadState('networkidle');

  // Compare against stored baseline screenshot
  await expect(page).toHaveScreenshot('homepage.png', {
    maxDiffPixels: 100,        // allow up to 100 different pixels
    threshold: 0.1,            // 10% color difference tolerance per pixel
    animations: 'disabled'     // disable animations for consistent screenshots
  });
});

/* Using pixelmatch for custom comparison */
const pixelmatch = require('pixelmatch');
const { PNG } = require('pngjs');
const fs = require('fs');

function compareImages(img1Path, img2Path, diffPath) {
  const img1 = PNG.sync.read(fs.readFileSync(img1Path));
  const img2 = PNG.sync.read(fs.readFileSync(img2Path));
  const { width, height } = img1;
  const diff = new PNG({ width, height });

  const numDiffPixels = pixelmatch(
    img1.data, img2.data, diff.data,
    width, height,
    { threshold: 0.1 }
  );

  fs.writeFileSync(diffPath, PNG.sync.write(diff));

  const percentDiff = (numDiffPixels / (width * height) * 100).toFixed(2);
  console.log(`Diff: ${numDiffPixels} pixels (${percentDiff}%)`);
  return numDiffPixels;
}

// Fail CI if more than 0.1% of pixels changed
const diff = compareImages('baseline.png', 'current.png', 'diff.png');
if (diff / (1920 * 1080) > 0.001) {
  process.exit(1); // fail the build
}

Animated GIF Frame Comparison

The viewer compares animated GIFs frame by frame to detect animation regressions:

/* Frame-by-frame comparison */

loading-spinner-v1.gif  vs  loading-spinner-v2.gif

Frame 1 (0ms):   ✓ Identical
Frame 2 (50ms):  ✓ Identical
Frame 3 (100ms): ✗ Different — rotation angle changed
Frame 4 (150ms): ✗ Different — rotation angle changed
Frame 5 (200ms): ✓ Identical
...

/* Diff summary */
Total frames:     12
Identical frames:  8 (67%)
Changed frames:    4 (33%)
Issue: Frames 3-6 have incorrect rotation angles
       Spinner rotates 45° per frame in v1
       Spinner rotates 30° per frame in v2 (slower animation)

/* Common animation regression causes */
- CSS animation duration changed
- Keyframe percentages modified
- Transform values updated
- Frame rate changed in GIF export settings

Frequently Asked Questions

Simply enter your data, click the process button, and get instant results. All processing happens in your browser for maximum privacy and security.

Yes! Image Diff Viewer is completely free to use with no registration required. All processing is done client-side in your browser.

Absolutely! All processing happens locally in your browser. Your data never leaves your device, ensuring complete privacy and security.