Website monitoring with screenshots: detect visual changes automatically

Website monitoring with screenshots: detect visual changes automatically

Build a visual watchdog for your sites — or your competitors'.

March 28, 2026 · 8 min read

Website monitoring usually means uptime checks (is it responding?) and performance monitoring (how fast?). Visual monitoring adds a third dimension: does the page still look right? It catches problems that traditional monitoring misses — broken CSS, missing images, layout shifts from third-party script updates, and accidental content changes.

Use cases

Production monitoring: Capture your own pages on a schedule to detect visual regressions that slip through CI. Especially valuable for e-commerce sites where a broken checkout page costs real money.

Competitor watching: Track competitors' pricing pages, feature lists, and landing pages. Get notified when they change their pricing or launch a new product.

Compliance: Some regulated industries require visual records of published content. Periodic screenshots create an auditable visual history.

Client reporting: Agencies can show clients visual proof that their sites haven't been defaced or broken.

Architecture

A visual monitoring system has three components: scheduled capture, pixel diff, and alerting.

1. Scheduled capture

Use a cron job, scheduled Lambda, or Cloudflare Worker to capture target pages at regular intervals (hourly, daily, or on-demand):

// capture.js — runs on schedule
const urls = [
  'https://yoursite.com',
  'https://yoursite.com/pricing',
  'https://competitor.com/pricing',
];

for (const url of urls) {
  const response = await fetch(
    'https://api.nightglass.xyz/api/v1/screenshot',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`,
      },
      body: JSON.stringify({ url, width: 1440, height: 900 }),
    }
  );

  const buffer = Buffer.from(await response.arrayBuffer());
  await saveToStorage(`screenshots/${slug(url)}/${Date.now()}.png`, buffer);
}

2. Pixel diff

Compare the new capture against the previous one. ImageMagick's compare command works well:

compare -metric AE previous.png current.png diff.png 2>&1

This outputs the number of differing pixels and generates a visual diff image (red highlights where changes occurred). In Node.js, the pixelmatch library does the same thing:

import pixelmatch from 'pixelmatch';
import { PNG } from 'pngjs';

const img1 = PNG.sync.read(fs.readFileSync('previous.png'));
const img2 = PNG.sync.read(fs.readFileSync('current.png'));
const diff = new PNG({ width: img1.width, height: img1.height });

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

const changePercent = mismatch / (img1.width * img1.height);
if (changePercent > 0.01) {
  // More than 1% of pixels changed — alert
  await sendAlert(url, changePercent, diff);
}

3. Alerting

When the diff exceeds your threshold, send a notification — Slack webhook, email, PagerDuty, whatever your team uses. Include the diff image so the recipient can see exactly what changed.

Threshold tuning

A 0% threshold produces too many false positives (anti-aliasing, dynamic ads, timestamps). Start at 1% and adjust based on your pages. Pages with dynamic content (news feeds, carousels) need higher thresholds or element-level masking.

Ready-made tools: Visualping, ChangeTower, and Hexowatch offer visual monitoring as a service. The DIY approach above is cheaper at scale and gives you more control — but takes more setup. For the screenshot capture component, nightglass handles the browser complexity.

To run this at volume, the scale architecture guide covers queue, worker, and storage patterns. For testing your own UI for regressions (rather than external sites), visual regression testing uses the same pixel-diff approach. For full-page capture accuracy, the full-page screenshot guide covers lazy loading and scroll gotchas.