How to Self-Host Changedetection.io: Website Change Monitoring 2026
TL;DR
Changedetection.io (Apache 2.0, ~18K GitHub stars, Python) monitors any website for changes and alerts you. Use it to track product prices, monitor competitor websites, watch for policy updates, or get notified when a sold-out item comes back in stock. Visualping charges $14/month for 25 checks. Changedetection.io is free and self-hosted with unlimited checks.
Key Takeaways
- Changedetection.io: Apache 2.0, ~18K stars, Python — website change monitoring with unlimited checks
- Visual diff: See exactly what changed — highlighted diff view
- CSS selectors: Monitor only a specific section of a page (price div, stock status, etc.)
- JavaScript rendering: Playwright integration handles SPAs and dynamic pages
- Price tracking: Extract and track numeric values over time
- Alerts: Notify via email, Slack, Discord, Telegram, ntfy, and 80+ more
Part 1: Docker Setup
# docker-compose.yml
services:
changedetection:
image: ghcr.io/dgtlmoon/changedetection.io:latest
container_name: changedetection
restart: unless-stopped
ports:
- "5000:5000"
volumes:
- changedetection_data:/datastore
environment:
BASE_URL: "https://watch.yourdomain.com"
TZ: America/Los_Angeles
# Optional: Playwright for JavaScript-heavy sites:
playwright-chrome:
image: browserless/chrome:latest
container_name: playwright-chrome
restart: unless-stopped
environment:
SCREEN_WIDTH: 1920
SCREEN_HEIGHT: 1024
DEFAULT_LAUNCH_ARGS: '["--no-sandbox"]'
volumes:
changedetection_data:
docker compose up -d
Visit http://your-server:5000
Part 2: HTTPS with Caddy
watch.yourdomain.com {
reverse_proxy localhost:5000
}
Part 3: Add Your First Watch
Basic URL watch (entire page)
- + Watch URL →
https://example.com/product - Check interval: Every 4 hours
- Save
On next check, Changedetection snapshots the page. On subsequent checks, it diffs the new content against the snapshot and alerts on any change.
Target a specific element (CSS selector)
For price tracking, monitor only the price element:
URL: https://amazon.com/dp/PRODUCT_ID
Filter: CSS selector → span.price, #priceblock_ourprice, .a-price
Common selectors:
/* Amazon price: */
.a-price .a-offscreen
/* Best Buy price: */
.priceView-customer-price span
/* Walmart price: */
[itemprop="price"]
/* Generic */
[class*="price"]
JavaScript-rendered pages (SPAs)
For sites that load content via JavaScript:
- Edit Watch → Fetch → Use Browser Steps (Playwright)
- Select browser:
Playwright Chrome - Optional: Add browser steps (click, scroll, wait for element)
Part 4: Notification Setup
ntfy (push notifications to phone)
Settings → Notifications → + Add notification
Type: ntfy
ntfy URL: https://ntfy.yourdomain.com/price-alerts
Priority: High
Telegram
Type: Telegram
Bot Token: your-bot-token
Chat ID: your-chat-id
Settings → SMTP:
SMTP Server: mail.yourdomain.com
Port: 587
Use TLS: Yes
Username: alerts@yourdomain.com
Password: your-password
From: alerts@yourdomain.com
Slack / Discord webhooks
Type: Slack or Discord
Webhook URL: https://hooks.slack.com/services/...
Part 5: Use Cases
Price tracking
URL: https://store.com/product-page
CSS Filter: .product-price
Alert condition: Price changes
Notification: Telegram/ntfy
Set up a condition:
- Alert when price decreases (
.product-pricevalue goes down) - Alert when stock status changes from "Out of Stock" to "In Stock"
Competitor monitoring
URL: https://competitor.com/pricing
Check interval: Daily
Alert: Any change on the pricing page
Policy / terms change tracking
URL: https://service.com/terms-of-service
Check interval: Weekly
Alert: Any change
Notification: Email
Government/public data
URL: https://city.gov/permits/new-permits
Check interval: Daily
CSS Filter: .permit-list
Alert: New content added
Job postings
URL: https://company.com/careers
CSS Filter: .job-listing
Alert: New items added
Part 6: Advanced Filtering
Include/Exclude text filters
# Only alert if the change contains these words:
Include text: "In Stock", "Available", "$"
# Ignore changes containing these words (reduces noise):
Exclude text: "Advertisement", "Related products", "Also viewed"
Regex filter
# Extract only specific values using regex:
# Filter type: Regex
# Pattern: \$[\d,]+\.?\d*
# This extracts all dollar prices from the page
XPath selectors
//div[@class='product-price']//span[@itemprop='price']
Part 7: Browser Steps (Playwright Automation)
For sites that require interaction before showing content:
Browser Steps:
1. Wait for element: .product-price
2. Click: [data-tab="pricing"] (if content is behind a tab)
3. Scroll to element: #product-details
4. Wait 2000ms (for animations to complete)
5. Take snapshot
Login-protected pages
Browser Steps:
1. Navigate to: https://site.com/login
2. Fill [name="username"]: your-username
3. Fill [name="password"]: your-password
4. Click: [type="submit"]
5. Wait for navigation
6. Navigate to: https://site.com/protected-page
Part 8: API
# List watches:
curl "https://watch.yourdomain.com/api/v1/watch" | jq '.[].url'
# Add a watch:
curl -X POST "https://watch.yourdomain.com/api/v1/watch" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/product",
"tag": "price-tracking",
"time_between_check": {"hours": 4},
"include_filters": [".product-price"]
}'
# Trigger immediate check:
curl -X GET "https://watch.yourdomain.com/api/v1/watch/UUID/history" | jq '.'
# Get watch diff:
curl "https://watch.yourdomain.com/api/v1/watch/UUID/history/latest"
Maintenance
# Update:
docker compose pull
docker compose up -d
# Backup:
tar -czf changedetection-backup-$(date +%Y%m%d).tar.gz \
$(docker volume inspect changedetection_changedetection_data --format '{{.Mountpoint}}')
# Logs:
docker compose logs -f changedetection
# Remove old snapshots (auto-cleaned, or manually):
# Settings → Maintenance → Purge old snapshots
See all open source monitoring tools at OSSAlt.com/categories/devops.