Visual monitoring catches problems that traditional uptime checks miss. A website can return HTTP 200 while displaying a broken layout, missing images, or an error message in the page body. Automated screenshot monitoring captures what users actually see.
Why Monitor with Screenshots?
- Visual regression detection — catch CSS breaks, missing images, and layout shifts that don't trigger HTTP errors.
- Content verification — confirm that pricing, product listings, or legal pages display the correct information.
- Competitor tracking — monitor competitor websites for design changes, new features, or pricing updates.
- Compliance records — maintain timestamped visual records of web pages for legal or regulatory purposes.
- Downtime evidence — screenshot captures provide visual proof of outages beyond simple ping checks.
No Code Required: Scheduled Captures
If you don't want to run a script at all, Site-Shot now does the scheduling for you: create a schedule in the browser — URL, capture settings, cadence — and it captures the page daily (or weekdays, or weekly), files every shot in your library, and keeps a ledger of every run including failures and skips. It's included with any paid plan. See the walkthrough in How to Automatically Screenshot a Website Every Day.
One honest limit: built-in schedules are an archive, not an alarm system — they capture and file every run, but they don't compare captures or alert you when a page changes. That part stays DIY, and the rest of this guide covers it: the API route, the right choice when you want captures wired into your own pipeline, storage, or diffing.
Basic Monitoring Script (Python)
Here's a Python script that captures a screenshot and saves it with a timestamp:
import os
from datetime import datetime
import requests
API_URL = "https://api.site-shot.com/"
API_KEY = os.environ.get("SITESHOT_API_KEY", "YOUR_API_KEY")
OUTPUT_DIR = "screenshots"
def capture(url, label="site"):
os.makedirs(OUTPUT_DIR, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{label}_{timestamp}.png"
filepath = os.path.join(OUTPUT_DIR, filename)
response = requests.get(API_URL, params={
"url": url,
"userkey": API_KEY,
"width": 1280,
"height": 1024,
"format": "png",
"no_ads": 1,
"no_cookie_popup": 1,
}, timeout=70)
if response.status_code == 200:
with open(filepath, "wb") as f:
f.write(response.content)
print(f"Captured: {filepath}")
else:
print(f"Error: HTTP {response.status_code}")
if __name__ == "__main__":
capture("https://your-website.com", label="homepage")
capture("https://your-website.com/pricing", label="pricing")
Scheduling Captures
With cron (Linux/macOS)
Run the script every hour:
0 * * * * /usr/bin/python3 /path/to/monitor.py
With Task Scheduler (Windows)
Create a scheduled task that runs python monitor.py at your desired interval.
With GitHub Actions
name: Screenshot Monitor
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
jobs:
capture:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install requests
- run: python monitor.py
env:
SITESHOT_API_KEY: ${{ secrets.SITESHOT_API_KEY }}
- uses: actions/upload-artifact@v4
with:
name: screenshots-${{ github.run_number }}
path: screenshots/
Where this runs, and the catch: each run executes on a fresh, newly-provisioned GitHub-hosted VM, so nothing persists on the machine between runs — the screenshots survive only because upload-artifact attaches them to the workflow run, where you download them from the run's page. Three limits matter (GitHub's rules as of August 2026): artifacts are deleted after 90 days by default; the schedule trigger is best-effort — runs can be delayed at busy times and occasionally dropped; and in a public repository scheduled workflows are switched off automatically after 60 days without repo activity. Keep the API key in an Actions secret (as above), never in the file. In short: GitHub Actions is a decent scheduler but a poor archive — if you want a history that keeps itself, that's what scheduled captures are for.
Monitoring Multiple Pages
PAGES = [
("https://your-site.com/", "homepage"),
("https://your-site.com/pricing", "pricing"),
("https://your-site.com/docs", "docs"),
("https://competitor.com/", "competitor"),
]
for url, label in PAGES:
capture(url, label=label)
Detecting Visual Changes
Compare consecutive screenshots using image diffing. A simple pixel-comparison approach:
from PIL import Image
import numpy as np
def images_differ(path_a, path_b, threshold=0.01):
"""Return True if more than `threshold` fraction of pixels differ."""
img_a = np.array(Image.open(path_a))
img_b = np.array(Image.open(path_b))
if img_a.shape != img_b.shape:
return True
diff_pixels = np.sum(img_a != img_b) / img_a.size
return diff_pixels > threshold
When a change is detected, send an alert via email, Slack, or your preferred notification channel.
Tips for Reliable Monitoring
- Use
no_ads=1andno_cookie_popup=1to remove dynamic elements that change between captures and create false positives. - Set a consistent viewport (e.g., 1280×1024) so screenshots are always comparable.
- Use
delay_time=3000for pages with heavy JavaScript rendering to ensure all content is loaded. - Capture from a fixed country using the
countryparameter (ISO code, e.g.country=US) to avoid geo-based content variations — see how country capture works. - Store screenshots with timestamps for audit trails and historical comparison.
Full Page Monitoring
For pages where content below the fold matters (e.g., long pricing pages), use full page capture:
response = requests.get(API_URL, params={
"url": url,
"userkey": API_KEY,
"full_size": 1,
"max_height": 10000,
"format": "jpeg", # JPEG for smaller files in archives
"no_ads": 1,
"no_cookie_popup": 1,
}, timeout=70)
FAQ
Can Site-Shot detect page changes for me?
No — and that's deliberate. Site-Shot's scheduled captures are an archive, not an alarm system: they capture a page on a cadence and file every shot in your library, but they don't diff images or send change alerts. For change detection, use the DIY route in this guide — capture via the API, compare consecutive shots, and send alerts through your own channel.
Do I need to write code to monitor a website with screenshots?
Not for the capture part. Site-Shot's built-in scheduled captures run from the browser: pick a URL, capture settings, and a cadence, and every shot lands in your library with a ledger of every run — included with any paid plan. Code is only needed for the custom parts: your own storage, image diffing, or alerting.
How often should I capture a page for monitoring?
Match the cadence to how fast the page changes. With your own cron you can run the script hourly or more often, within your plan's capture volume. Site-Shot's built-in schedules are designed for daily, weekday, or weekly cadences — the right fit for pricing pages, landing pages, and compliance records.
Next Steps
- Set up the Site-Shot API with your API key
- Create a monitoring script for your key pages
- Schedule it with cron, GitHub Actions, or your CI/CD pipeline — or skip the script and use scheduled captures
- Add image diffing and alerting for automated change detection
Try the free no-signup screenshot tool or compare API plans on the pricing page.