Skip to main content

Open-source alternatives guide

Self-Host Changedetection.io for Website Change Monitoring 2026

Self-host Changedetection.io in 2026. Apache 2.0, ~18K stars, Python — monitor any website for changes. Price tracking, product availability, content.

·OSSAlt Team
Share:

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)

  1. + Watch URLhttps://example.com/product
  2. Check interval: Every 4 hours
  3. 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:

  1. Edit Watch → Fetch → Use Browser Steps (Playwright)
  2. Select browser: Playwright Chrome
  3. 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

Email

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-price value 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

Why Self-Host Changedetection.io

The economics here are straightforward. Visualping's $14/month plan allows 25 URLs checked every 6 hours. Distill.io's Pro plan runs $14/month for 25 checks per hour. If you have 50 URLs to monitor — a modest number for competitive intelligence, price tracking, and compliance monitoring combined — you're looking at $28-50/month on SaaS platforms, or $672-$600/year.

Changedetection.io self-hosted on a $6/month VPS handles hundreds of URLs with no per-check fees. The math is compelling even at small scale, and it becomes overwhelming at large scale. A company monitoring 500 competitor pages, product prices, and regulatory sites would pay $200+/month on SaaS. Self-hosted, it's just compute.

Data privacy is significant with change detection specifically. Your watchlist reveals what you care about — competitor pricing pages, specific products you're tracking, regulatory filings you're watching. That's competitive intelligence sitting on a third-party's servers. Self-hosting keeps your monitoring strategy private.

The Playwright integration is another major differentiator. Most SaaS change detection tools either don't support JavaScript-rendered sites, or charge a premium for it. With self-hosted Changedetection.io, you can monitor SPAs, sites behind login walls, and pages that require complex interactions — all at no extra cost.

When NOT to self-host: If you only need to monitor 5-10 URLs occasionally, a free tier on Visualping or Distill.io is genuinely easier than maintaining a server. Also, Changedetection.io requires periodic maintenance — Playwright updates, container restarts, storage management for snapshots. If you have no one technical to handle that, a managed service is more reliable.

Prerequisites

Changedetection.io is one of the simpler self-hosted applications to run, but a few requirements matter for a reliable setup.

Server specs: The base Changedetection container is lightweight — 256MB RAM is sufficient for simple HTTP checks. However, if you enable Playwright for JavaScript rendering, plan for 1GB+ RAM. The Browserless/Chrome container alone uses 300-500MB at idle and spikes higher when rendering complex pages. A $6-10/month VPS with 2GB RAM handles most setups comfortably. Check our VPS comparison for self-hosters to pick a provider with good network performance, since Changedetection is network-bound.

Operating system: Ubuntu 22.04 LTS. Docker's performance on Ubuntu is well-tested, and the long support window means less OS maintenance over time.

Storage: Each watched URL stores a snapshot per check interval. For 100 URLs checked every 4 hours, you accumulate ~600 snapshots/day. Default snapshot retention is configurable — set a reasonable limit (30-90 days) in Settings → Maintenance or you'll fill your disk within weeks.

Network: Your server needs outbound HTTPS access to the sites you're monitoring. Some sites block known cloud provider IP ranges (AWS, GCP, Hetzner). If you encounter blocking, a residential proxy service can route checks through clean IPs.

Skill level: Beginner-friendly. This is a single Docker container with a web UI. If you can run docker compose up -d, you can run Changedetection.

Production Security Hardening

Changedetection.io has no authentication by default — anyone who reaches port 5000 can view your watchlist and change configuration. Before exposing it to the internet, follow the self-hosting security checklist and implement these steps:

Firewall (UFW): Block direct access to port 5000 — only allow access through your reverse proxy.

sudo ufw default deny incoming
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Do NOT expose 5000 directly
sudo ufw enable

Enable authentication: In Settings → Security, set a username and password. This is basic auth, but it prevents casual exposure. For stronger protection, put Changedetection behind a Caddy reverse proxy with forward auth to an identity provider.

Secrets management: If you're storing notification credentials (SMTP password, Telegram bot token, Slack webhook), these live in the datastore volume. Keep that volume encrypted and back it up carefully. Never commit the .env file to version control:

# .env
BASE_URL=https://watch.yourdomain.com
# Add to .gitignore:
echo ".env" >> .gitignore

Playwright isolation: The Chrome container runs with --no-sandbox for compatibility. This is acceptable since it's visiting external sites in an isolated container, but you should not run Changedetection on the same machine as sensitive databases without network isolation. Use Docker networks to prevent the Playwright container from reaching your internal services.

Disable SSH password authentication: Edit /etc/ssh/sshd_config: set PasswordAuthentication no and PermitRootLogin no. Use SSH keys only. Restart: sudo systemctl restart ssh.

Automatic security updates:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

Regular backups: The entire state lives in the changedetection_data volume — watches, snapshots, and notification configs. Back this up daily. See automated server backups with restic for a set-and-forget backup solution.

Building a Practical Monitoring Strategy

Raw change detection is powerful, but using it effectively requires a strategy that balances coverage, alert noise, and maintenance overhead.

The biggest mistake new Changedetection.io users make is monitoring too much without filtering. Adding 50 URLs at 4-hour check intervals and receiving alerts on every detected change quickly produces alert fatigue — you'll start ignoring notifications within a week. The solution is layering. Start with a broad check on the whole page to confirm changes happen, then refine to a specific CSS selector that targets only the content you care about. Add include/exclude text filters as a third layer to eliminate known noise sources (ads, rotating recommendations, session-specific content).

Check interval selection matters more than people realize. Many retailers implement rate limiting that blocks IP addresses making too many requests. A 30-minute check interval on 100 Amazon product pages is a reliable way to get your server's IP blocked. For e-commerce price tracking, 4-6 hour intervals are both polite and practically sufficient — prices rarely change multiple times per day outside of flash sales. For competitor blog monitoring where you want to catch new posts, daily checks are entirely adequate.

The Playwright integration deserves a dedicated approach for complex sites. Not every site needs a headless browser — using Playwright for every check burns 5-10x more resources than a simple HTTP fetch. Reserve Playwright for sites that genuinely require JavaScript rendering: single-page applications built with React/Vue/Angular, sites that load price data via AJAX, and pages that require user interaction before showing content. Use the regular fetch mode as your default and only upgrade to Playwright when you confirm the simple mode isn't capturing all changes.

Group your watches by use case and tag them accordingly. Tags in Changedetection.io filter the dashboard — having 50 untagged watches is harder to manage than 50 watches organized into "price-tracking," "competitor," and "compliance" groups. Apply tags at creation time, not retroactively.

For teams, the API (Part 8) opens programmatic watch management. You can build a script that reads a CSV of URLs and creates watches with consistent settings, or write a workflow that automatically adds new competitor pages when your team discovers them.

Troubleshooting Common Issues

"Fetch error" on every check — site isn't being monitored

Most fetch errors are one of three things: the site is blocking your server's IP range (common with AWS/Hetzner IPs for e-commerce sites), the site requires JavaScript rendering (use Playwright), or your server has no outbound internet access. Check the error details in the watch history — it logs the HTTP response code. A 403 Forbidden means IP blocking; a timeout means network issues.

Playwright checks always fail or time out

Verify the Playwright/Chrome container is actually running: docker compose ps. If it's restarting in a loop, check docker compose logs -f playwright-chrome. Common issues: insufficient /dev/shm (Chrome needs shared memory — add shm_size: '1gb' to the playwright service), or the site requires a more recent browser version than the Browserless image provides. Try updating with docker compose pull.

Getting too many false positive alerts

If Changedetection is alerting on every check due to dynamic content (ads, timestamps, session tokens), use CSS selectors to target only the content you care about. The "Ignore text" filter is also powerful — add patterns for rotating ad content, timestamps, and recommendation widgets that change on every page load.

Notifications not sending

Test your notification setup from Settings → Notifications → Test. If the test succeeds but production alerts don't fire, check whether the watch has a filter condition that's not being met. Also verify your check interval — if you have "only notify on content change greater than X%" and the change is small, it won't trigger.

Disk filling up

Snapshot accumulation is the most common storage issue. Each watch stores one snapshot per check. Go to Settings → Maintenance → and configure snapshot retention to 30 days maximum. You can also manually purge old snapshots per-watch. For large deployments (100+ URLs), monitor disk usage with df -h and set up an alert when usage exceeds 70%.

Container won't start after update

Occasionally Changedetection updates include datastore format changes. If the container crashes on startup after a pull, check logs with docker compose logs changedetection. Look for migration errors. The project documents breaking changes in release notes — check GitHub before pulling major version updates.

Changedetection pairs naturally with n8n for automated response workflows. When a price drops or a product returns to stock, an n8n webhook can trigger downstream actions — sending a push notification, posting to Slack, creating a task in your project management tool, or placing an order via a shopping API. The combination of Changedetection for monitoring and n8n for automation gives you a complete price-watch and content-monitoring system without any monthly fees. Both run as Docker containers and can be managed from the same Portainer or Dockge instance.

See all open source monitoring tools at OSSAlt.com/categories/devops.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.