Back to Blog
Feature March 28, 2026 · 4 min read

Visual Diff API: Pixel-Perfect Change Detection for Any Two Pages

Compare any two URLs or HTML strings pixel-by-pixel and get a highlighted diff image, changed pixel count, and percentage. One API call, no browser in your stack.

You shipped a CSS change. The login page looks fine. But the pricing page? The cards overlapped and nobody noticed for three days. Unit tests do not catch layout drift, missing assets, or subtle color shifts — visual diffs do.

Visual regression compares what users actually see. When something changes between two renders, you get proof: a diff image, counts, and a percentage. That is what the Visual Diff API is for.

What Visual Diff does

Send two sources — either url_a / url_b or html_a / html_b — and PageBolt returns a single response with:

  • Diff image — a PNG where changed pixels are highlighted (red) against the baseline
  • changed_pct — percentage of pixels that differ
  • changed_pixels and total_pixels — raw counts for thresholds and reporting
  • duration_ms — how long the comparison took

One HTTP request. No Playwright, no Docker, no headless browser running in your infrastructure.

How it works

Both pages are rendered in parallel in Chromium at the same viewport size. Screenshots are then compared with pixelmatch for a deterministic pixel-level diff. If the two captures have different dimensions, the smaller canvas is padded so the comparison stays well-defined.

API example

curl -X POST https://pagebolt.dev/api/v1/diff \
  -H "x-api-key: $PAGEBOLT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url_a": "https://staging.myapp.com",
    "url_b": "https://production.myapp.com",
    "threshold": 0.1,
    "width": 1280,
    "blockBanners": true
  }'

Example response:

{
  "changed_pct": 2.34,
  "changed_pixels": 21542,
  "total_pixels": 921600,
  "diff_image": "data:image/png;base64,...",
  "duration_ms": 1842
}

Use cases

  • CI/CD visual regression — screenshot staging vs production (or vs a baseline) before you merge or deploy
  • Website monitoring — run periodic diffs to catch unauthorized or accidental changes
  • A/B testing verification — confirm the correct variant is live on a URL
  • Design QA — compare a Figma export or mock rendered as HTML against the real implementation

CI/CD integration

Here is a GitHub Actions step that calls the diff API and fails the job if the change percentage exceeds 5%:

- name: Visual diff check
  run: |
    RESULT=$(curl -s -X POST https://pagebolt.dev/api/v1/diff \
      -H "x-api-key: ${{ secrets.PAGEBOLT_API_KEY }}" \
      -H "Content-Type: application/json" \
      -d "{\"url_a\": \"$STAGING_URL\", \"url_b\": \"$PRODUCTION_URL\", \"threshold\": 0.1}")
    PCT=$(echo $RESULT | jq -r '.changed_pct')
    echo "Visual change: ${PCT}%"
    if (( $(echo "$PCT > 5" | bc -l) )); then
      echo "::error::Visual diff exceeds 5% threshold"
      exit 1
    fi

Install jq and bc on the runner if they are not already available, and set STAGING_URL / PRODUCTION_URL via repository or environment variables.

Node.js SDK

const res = await fetch('https://pagebolt.dev/api/v1/diff', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.PAGEBOLT_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url_a: 'https://staging.myapp.com',
    url_b: 'https://production.myapp.com',
    threshold: 0.1,
  }),
});
const data = await res.json();
// data.diff_image is a base64 PNG; data.changed_pct is the % difference

Python SDK

import requests

resp = requests.post(
    "https://pagebolt.dev/api/v1/diff",
    headers={"x-api-key": PAGEBOLT_KEY},
    json={
        "url_a": "https://staging.myapp.com",
        "url_b": "https://production.myapp.com",
        "threshold": 0.1,
    },
)
data = resp.json()
# data["diff_image"] is a base64 PNG; data["changed_pct"] is the % difference

All parameters

Quick reference for the request body (pair url_a/url_b or html_a/html_b):

Parameter Description
url_aFirst page URL
url_bSecond page URL
html_aFirst page as HTML string (alternative to URLs)
html_bSecond page as HTML string
thresholdSensitivity 0–1; default 0.1
widthViewport width in pixels
heightViewport height in pixels
darkModeEmulate prefers-color-scheme: dark
blockBannersHide cookie / consent banners
blockAdsBlock ad requests
cookiesCookies to send with navigations
headersExtra HTTP headers
authorizationAuthorization for protected pages
viewportDeviceNamed device preset (e.g. phone / tablet profiles)

The free tier includes 100 requests per month. Each visual diff costs 1 request. Grab an API key on signup and see full request/response details in the documentation.

Get Started Free

100 requests/month, no credit card

Visual diff costs one request per comparison — pixel-perfect change detection without running a browser in your stack. Create a free account or read the API docs.

Get Your Free API Key →