Visual Regression Monitor — Website Screenshot Comparison avatar

Visual Regression Monitor — Website Screenshot Comparison

Pricing

from $0.01 / actor start

Go to Apify Store
Visual Regression Monitor — Website Screenshot Comparison

Visual Regression Monitor — Website Screenshot Comparison

Monitor websites for visual regressions. Capture baseline screenshots, compare against new captures, and generate pixel-accurate diff reports with highlighted changes.

Pricing

from $0.01 / actor start

Rating

0.0

(0)

Developer

Perry AY

Perry AY

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Visual Regression Monitor 🎯 — Detect Website Changes with Pixel-Perfect Diff Analysis

Capture website screenshots and compare them pixel-by-pixel to detect visual regressions. Generate annotated diff images, monitor pages on a schedule, and receive webhook alerts when changes are detected. Uses a headless Chromium browser for accurate, real-world screenshots.


What does it do?

The Visual Regression Monitor automates visual quality assurance for web pages. It takes full-page or viewport screenshots using headless Chromium, stores them as baselines in Apify's Key-Value Store, and then compares subsequent captures against those baselines pixel-by-pixel. When differences are found, it generates three-panel annotated diff images showing the baseline, current state, and highlighted changes.

Key capabilities:

  • Baseline capture — Take screenshots of any URL and save them as reference images
  • Visual comparison — Compare live pages against stored baselines with pixel-level diff reporting
  • Batch processing — Compare multiple URLs concurrently for efficient monitoring
  • Annotated diff reports — Generate HTML summary reports with per-URL match/mismatch status
  • Webhook alerts — Send JSON alert payloads when visual mismatches are detected (ideal for CI/CD pipelines)
  • Configurable thresholds — Set a diff percentage tolerance to ignore minor rendering differences
  • Custom viewport — Control browser width, height, and full-page capture

Who is it for?

PersonaUse Case
QA EngineerAutomate visual regression testing in CI/CD pipelines
Front-End DeveloperCatch unintended UI changes before deployment
Site Reliability EngineerMonitor production pages for unexpected visual drift
Product ManagerVerify visual consistency across environments
Web AgencyScale visual QA across multiple client sites

Input Parameters

ParameterTypeDefaultDescription
modestringcapture-baselineOperation mode: capture-baseline, compare-baseline, batch-compare, or generate-diff-report
urlstringA single URL to process (ignored if urls is provided)
urlsarrayOne or more URLs to process (up to 50)
viewportWidthinteger1280Browser viewport width in pixels
viewportHeightinteger720Browser viewport height in pixels
fullPagebooleanfalseCapture the entire scrollable page
waitAfterLoadMsinteger2000Milliseconds to wait after page load before screenshot
diffThresholdnumber0.0Allowed diff percentage before flagging a mismatch
timeoutSecsinteger60Max seconds to wait for page navigation
webhookUrlstringURL for POST alerts when mismatches are detected

Quick Start

Capture Baselines

Start by capturing reference screenshots for the pages you want to monitor:

{
"mode": "capture-baseline",
"urls": ["https://example.com", "https://httpbin.org"],
"viewportWidth": 1280,
"viewportHeight": 720,
"fullPage": false
}

Baseline images are stored in your run's Key-Value Store under keys like baseline-example.com___ and baseline-httpbin.org___.

Compare to Baseline

After baselines are stored, compare the live pages:

{
"mode": "compare-baseline",
"urls": ["https://example.com", "https://httpbin.org"],
"diffThreshold": 2.0,
"webhookUrl": "https://hooks.example.com/visual-alerts"
}

This captures new screenshots, compares them pixel-by-pixel against the stored baselines, and generates annotated diff images in KVS. If the diff percentage exceeds the threshold, the URL is flagged as a mismatch.

Batch Compare

For larger workloads, use batch mode to compare multiple URLs concurrently:

{
"mode": "batch-compare",
"urls": [
"https://example.com",
"https://httpbin.org",
"https://www.google.com",
"https://github.com"
],
"diffThreshold": 1.0
}

All comparisons run concurrently via asyncio.gather with return_exceptions=True, so a failure on one URL does not affect others.

Generate Diff Report

After comparisons, generate an HTML report summarising all results:

{
"mode": "generate-diff-report"
}

The report is stored in KVS as report-latest.html and as a timestamped key. Open the KVS URL in your browser to view the dark-themed annotated report with per-URL match/mismatch status, diff percentages, and pixel counts.


Output

Each run pushes individual results to the default dataset. For comparison modes, each item contains:

FieldTypeDescription
urlstringThe URL that was processed
matchbooleanWhether the screenshot matched the baseline
diff_percentnumberPercentage of differing pixels
pixels_differentintegerRaw count of differing pixels
total_pixelsintegerTotal pixels in the screenshot
diff_kvs_keystringKVS key for the annotated diff PNG
baseline_kvs_keystringKVS key for the stored baseline image
compared_atstringISO 8601 comparison timestamp

For baseline captures, each item contains:

FieldTypeDescription
urlstringThe captured URL
successbooleanWhether capture succeeded
image_size_bytesintegerSize of the PNG in bytes
taken_atstringISO 8601 capture timestamp
errorstringError message if capture failed

API Usage

cURL

curl -X POST "https://api.apify.com/v2/acts/perryay~visual-regression-monitor/runs" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_APIFY_TOKEN" \
-d '{
"mode": "compare-baseline",
"urls": ["https://example.com"],
"diffThreshold": 2.0
}'

Python

import requests
response = requests.post(
"https://api.apify.com/v2/acts/perryay~visual-regression-monitor/runs",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_APIFY_TOKEN"
},
json={
"mode": "compare-baseline",
"urls": ["https://example.com"],
"diffThreshold": 2.0
}
)
print(response.json())

Node.js

const response = await fetch(
"https://api.apify.com/v2/acts/perryay~visual-regression-monitor/runs",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_APIFY_TOKEN"
},
body: JSON.stringify({
mode: "compare-baseline",
urls: ["https://example.com"],
diffThreshold: 2.0
})
}
);
const data = await response.json();
console.log(data);

Use Cases

  • CI/CD visual regression testing — Run compare-baseline after deployments to catch unintended UI changes
  • Scheduled page monitoring — Use Apify's scheduler to run comparisons hourly/daily and get webhook alerts on mismatches
  • Multi-environment comparison — Capture baselines from staging, compare against production
  • Content verification — Detect unexpected changes to critical pages (pricing, landing pages, legal pages)
  • Cross-browser QA — Run the same URLs at different viewport sizes

FAQ

General

What is visual regression testing? Visual regression testing compares screenshots of a web page taken at different times to detect unintended visual changes. It catches layout shifts, missing elements, font changes, and styling regressions that functional tests might miss.

Do I need to run capture-baseline first? Yes. The compare-baseline and batch-compare modes require baseline images to exist in KVS. Run capture-baseline first to create them.

How are baselines stored? Baseline images are stored in your run's Key-Value Store under keys prefixed with baseline-. They persist between runs and are accessible via the Apify Console or API.

What happens if the viewport dimensions change? If a comparison detects that the baseline and current screenshot have different dimensions, the baseline is automatically resized to match the current image using Lanczos resampling. A warning is logged.

Can I use this for responsive design testing? Yes. Run the same URLs with different viewportWidth and viewportHeight settings to capture baselines for each breakpoint, then compare against the matching breakpoint.

What file format are the diff images? All diff images are generated as PNG with a three-panel layout: baseline (left), current (middle), and changes highlighted in red (right). A status bar at the bottom shows the URL, diff percentage, and pixel counts.

Webhooks

What does the webhook payload look like?

{
"event": "visual-regression-alert",
"mode": "compare-baseline",
"timestamp": "2026-07-27T12:00:00.000Z",
"results": {
"total_urls": 5,
"failures": 2,
"successes": 3
}
}

How do I set up scheduled monitoring? Use Apify's built-in scheduler: create a task with mode: compare-baseline, set the desired URLs and threshold, and configure a daily or hourly schedule with a webhookUrl to receive alerts.

Technical

What browser engine is used? Headless Chromium via Playwright. The Docker image (apify/actor-python-playwright) includes the Chromium browser binary pre-installed.

How accurate is the pixel comparison? It uses Pillow's ImageChops.difference() for exact pixel-level comparison. Each pixel channel is compared independently. The diffThreshold parameter lets you relax strictness: 0% = pixel-perfect, 5% = tolerant to minor antialiasing or font rendering differences.

How many URLs can I process in a single run? Up to 50 URLs per run. For larger workloads, split across multiple scheduled runs or tasks.

Does it support authentication-protected pages? Currently the actor does not include cookie/session management. You can use Apify's Proxy or custom headers for basic auth scenarios.

What happens if the page fails to load? The actor retries up to 3 times with exponential backoff (2s, 4s, 8s). If all attempts fail, the URL is reported with an error and no charge is applied for that item.

How are the annotated diff images generated? A three-panel composite is created using Pillow. Differing pixels are highlighted with a semi-transparent red overlay on the current screenshot. A dark-themed stats bar at the bottom shows the URL, diff percentage, total pixels, and match/mismatch status.


MCP Integration

Connect this actor to any AI assistant via the Apify MCP Server:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com"
}
}
}

Bearer token alternative (for headless clients like Cursor or VS Code):

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com",
"headers": {
"Authorization": "Bearer YOUR_APIFY_TOKEN"
}
}
}
}

On first connection, your browser opens to sign in to Apify and authorise access.

Example prompts for your AI assistant:



SEO Keywords

Visual regression testing, screenshot diff tool, pixel comparison, visual QA automation, CI/CD visual testing, website monitoring, UI regression detection, automated screenshot comparison, web page change detection, headless browser testing, visual regression monitor, Apify actor visual testing, front-end testing tool, visual diff report, cross-browser screenshot comparison, annotated diff images, webhook visual alerts, batch URL comparison, baseline screenshot capture, pixel-perfect comparison.