Build a visual change detection service that monitors URLs, captures screenshots on a schedule, and alerts your team when something changes. Powered by SnapAPI screenshot comparison.
// Capture and compare in one workflow
const baseline = readBaseline('https://example.com');
const current = await snapapi.screenshot({ url: 'https://example.com', full_page: true });
const diff = await compareImages(baseline, current);
if (diff.percentage > 1.0) {
await sendAlert({ url: 'https://example.com', diff });
}
A complete web monitoring service has three components: a scheduler that triggers captures on a defined interval, a comparison engine that diffs the new screenshot against the stored baseline, and an alerting layer that routes notifications based on diff severity.
SnapAPI provides the browser rendering layer. Your service handles scheduling (cron, AWS EventBridge, or a job queue), comparison (pixelmatch, sharp, or Jimp for Node.js; Pillow for Python), and alerting (Slack webhooks, PagerDuty, email via SendGrid). Each component is replaceable — start simple and add complexity as needed.
Store baselines in S3 with a key pattern like baselines/{hash(url)}/{timestamp}.png. On each monitoring run, fetch the most recent baseline, capture a new screenshot, compute the pixel diff, and store the new screenshot as the updated baseline if the diff is below your acceptance threshold. Alert when the diff exceeds the threshold and store the diff image as evidence.
For text content monitoring, use SnapAPI's extract endpoint instead of screenshot comparison. Define a schema that extracts the specific text fields you want to monitor — a price, a status message, a version number, or a news headline. Compare the extracted values against the stored baseline. This approach is faster and more precise than pixel comparison for text-based changes.
// Monitor a price with the extract endpoint
const resp = await fetch('https://api.snapapi.pics/v1/extract', {
method: 'POST',
headers: { 'X-Api-Key': process.env.SNAP_API_KEY },
body: JSON.stringify({
url: 'https://competitor.com/pricing',
schema: {
starter_price: { selector: '.plan-starter .price', transform: 'number' },
pro_price: { selector: '.plan-pro .price', transform: 'number' }
}
})
});
const { data } = await resp.json();
if (data.pro_price !== storedPrice) {
await sendAlert(`Pro plan price changed: ${storedPrice} → ${data.pro_price}`);
}
For large URL portfolios — hundreds or thousands of monitored pages — batch your monitoring jobs. Group URLs by monitoring frequency: high-priority pages every 15 minutes, standard pages hourly, archival checks daily. Use a job queue (BullMQ, Celery, Sidekiq) to manage concurrency and prevent API rate limit errors.
SnapAPI's Business plan at $299/month provides 500,000 calls per month. Monitoring 1,000 URLs every 15 minutes uses 96,000 captures per day — within the Business tier. For smaller portfolios, the Pro plan at $79/month (50,000 calls) supports monitoring 300 URLs at 15-minute intervals throughout the day.
Sign up at snapapi.pics to start building your monitoring service. The free tier includes 200 API calls per month — enough to prototype the full monitoring pipeline before committing to a paid plan.
When a monitoring run detects a change, route the alert through your existing notification infrastructure. For engineering teams, Slack webhooks provide immediate visibility — post the diff percentage, a thumbnail of the diff image, and a direct link to the monitored URL. For operations and compliance teams, email via SendGrid or Postmark provides a paper trail. For on-call workflows, PagerDuty or OpsGenie allows routing based on severity.
async function sendSlackAlert(url, diffPct, diffImageUrl) {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `:warning: Visual change detected on ${url}`,
attachments: [{
color: diffPct > 5 ? 'danger' : 'warning',
fields: [
{ title: 'Diff', value: diffPct.toFixed(2) + '%', short: true },
{ title: 'URL', value: url, short: false }
],
image_url: diffImageUrl
}]
})
});
}Use node-cron for simple interval-based monitoring in a single Node.js process. For production deployments, BullMQ with Redis provides job persistence, retry logic, rate limiting, and a dashboard for monitoring job health. AWS Lambda with EventBridge scheduler is a fully serverless option — trigger the Lambda on a cron schedule and it captures, compares, and alerts with no always-on server to manage.
Store monitoring configuration in a database: the URL, check interval, diff threshold, alert channels, and baseline image path. This allows dynamic configuration changes — adding new URLs, adjusting thresholds, pausing monitoring for a URL — without redeploying your service.
Beyond visual diff, use SnapAPI to verify that pages actually render correctly — not just return a 200 status code. A page that returns HTTP 200 but renders a blank white screen, an error boundary, or a "service unavailable" message is functionally down for users. Screenshot-based monitoring detects these rendering failures that HTTP health checks miss entirely.
import requests, base64
from PIL import Image
import io
def check_page_renders(url, api_key):
resp = requests.post(
'https://api.snapapi.pics/v1/screenshot',
headers={'X-Api-Key': api_key},
json={'url': url, 'width': 1280, 'height': 720}
)
img = Image.open(io.BytesIO(base64.b64decode(resp.json()['image'])))
# Check that the page is not blank (not mostly white/grey)
pixels = list(img.getdata())
unique_colors = len(set(pixels))
return unique_colors > 100 # Blank pages have very few unique colorsStore each monitoring run result in a time-series database (InfluxDB, TimescaleDB, or a simple Postgres table with timestamp). Record the URL, timestamp, diff percentage, and alert status. Query over rolling windows to calculate uptime percentage, mean time between visual incidents, and trend lines for specific pages.
Surface these metrics in a dashboard using Grafana, Metabase, or a simple HTML chart page rendered by your monitoring service itself. A status page showing uptime history and recent visual changes builds customer confidence and reduces support load.
Use the extract endpoint to monitor competitor pricing pages daily. Define a schema with CSS selectors for plan names and prices. Store results in a database and alert when a price changes. This gives your product and sales teams immediate visibility into competitor pricing moves without any manual research.
Legal teams monitor terms of service, privacy policies, and regulatory pages for changes. Capture a screenshot and extract the page text on a weekly schedule. Use a text diff library to detect content changes and generate a report for legal review. The screenshot serves as visual proof of the page state at each monitoring timestamp.
Run visual monitoring checks after each production deployment. Capture screenshots of your key pages immediately after deploy and compare against pre-deploy baselines. If visual diff exceeds threshold, trigger an automated rollback or alert the on-call engineer. This catches CSS regressions, broken deployments, and CDN caching issues within minutes of going live.
Sign up at snapapi.pics to start building your monitoring service today. The free tier provides 200 API calls per month — enough to prototype a complete monitoring pipeline for 5-10 URLs.
import requests, base64, os
from PIL import Image, ImageChops
import io, json
API_KEY = os.environ['SNAP_API_KEY']
def capture(url):
r = requests.post('https://api.snapapi.pics/v1/screenshot',
headers={'X-Api-Key': API_KEY},
json={'url': url, 'full_page': True, 'width': 1280})
return Image.open(io.BytesIO(base64.b64decode(r.json()['image'])))
def diff_pct(img1, img2):
if img1.size != img2.size:
img2 = img2.resize(img1.size)
diff = ImageChops.difference(img1, img2)
pixels = list(diff.getdata())
changed = sum(1 for p in pixels if max(p) > 10)
return changed / len(pixels) * 100
def monitor(url, baseline_path, threshold=1.0):
current = capture(url)
if not os.path.exists(baseline_path):
current.save(baseline_path)
return 0.0
baseline = Image.open(baseline_path)
pct = diff_pct(baseline, current)
if pct > threshold:
current.save(baseline_path) # Update baseline
return pct
return 0.0Run this script on a cron schedule (crontab, systemd timer, or GitHub Actions scheduled workflow) to monitor any URL at any interval. Combine with a Slack webhook notification on non-zero return values for instant alert delivery.
Web monitoring is most valuable when it is fully automated and requires zero human intervention for routine checks. The monitoring pipeline described here — schedule, capture, compare, alert — runs entirely unattended. Engineers are only paged when a real change is detected. Over time, with a well-tuned diff threshold and masked dynamic regions, false positive rates drop to near zero and the system builds trust as a reliable early warning tool. Sign up at snapapi.pics to start your monitoring service today.
SnapAPI supports all languages: Node.js, Python, Go, PHP, Ruby, Java, Rust, Swift, Kotlin, C#. SDKs at github.com/Sleywill. MCP server for Claude Code at npmjs.com/package/snapapi-mcp. Free tier: 200 calls/month, no card required.