Changedetection.io Setup: Monitor Webpage Changes and Get Alerts via Docker
Monitor webpage updates, price drops, and structural changes. Deploy changedetection.io via Docker Compose with automated notifications.
Changedetection.io Setup: Monitor Webpage Changes and Get Alerts via Docker
Keeping track of webpage updates, restock notifications, price drops, and visual changes on the modern web is increasingly difficult. Many sites rely heavily on client-side JavaScript rendering, single-page application (SPA) architectures, or implement anti-scraping protections (like Cloudflare) that block basic cURL requests.
Changedetection.io is the premier self-hosted solution for webpage change monitoring. By combining Changedetection.io with a dedicated headless Chrome rendering container (Browserless/Playwright), you can bypass basic scraping limitations, execute custom interactive scripts (like clicking buttons or logging in), filter out noisy layout shifts, and send instant alerts to dozens of destinations.
This guide provides a comprehensive, production-grade guide to deploying Changedetection.io on a virtual private server (VPS) using Docker Compose.
1. Architectural Overview
A robust self-hosted changedetection environment consists of two main decoupled components running inside a Docker network:
- Changedetection.io Core: The Flask-based web application. It handles the scheduler, database storage (YAML flat-files or SQLite), difference calculation (visual diffs, text diffs, HTML diffs), and notification dispatching.
- Playwright/Browserless (Headless Chrome): A browser-as-a-service container. When Changedetection.io encounters a Javascript-heavy page, it passes the URL to the Browserless container via a WebSocket connection. Browserless launches a Chromium instance, renders the page, executes scripts, and returns the fully rendered HTML or visual screenshot to the core application.
graph TD
Client[User Browser] -->|Port 5000 / Reverse Proxy| CD[Changedetection.io Core]
CD -->|WebSocket ws://browserless:3000| BL[Browserless/Playwright Container]
BL -->|Fetches Page| Web[Target Website]
CD -->|Apprise/Webhooks| Notify[Notifications: Discord, Telegram, Webhook]
CD -->|Volume Mount| Disk[(Persistent Storage)]
2. Production Docker Compose Configuration
Create a dedicated application directory on your VPS (e.g., /opt/changedetection) and populate the following docker-compose.yml.
This configuration includes: - Stealth settings for the Playwright engine to reduce detection by bot mitigation frameworks. - Resource limit controls on the Browserless container to prevent memory leaks from long-running Chrome processes. - Named networks and restart policies to ensure high availability.
version: '3.8'
services:
changedetection:
image: ghcr.io/dgtlmoon/changedetection.io:latest
container_name: changedetection
hostname: changedetection
restart: unless-stopped
ports:
- "127.0.0.1:5000:5000" # Bound to localhost for security behind a reverse proxy
volumes:
- changedetection-data:/datastore
environment:
# Link to the browserless service with stealth & security arguments
- PLAYWRIGHT_DRIVER_URL=ws://browserless:3000/?stealth=true&--disable-web-security=true
# Uncomment to secure with a base URL if needed
# - BASE_URL=https://monitor.yourdomain.com
depends_on:
- browserless
networks:
- monitor-network
browserless:
image: browserless/chrome:latest
container_name: browserless-chrome
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000" # Expose only locally
environment:
- SCREEN_WIDTH=1920
- SCREEN_HEIGHT=1080
- SCREEN_DEPTH=24
- MAX_CONCURRENT_SESSIONS=10 # Prevents CPU spikes by queuing excessive simultaneous requests
- MAX_QUEUE_LENGTH=20
- PREBOOT_CHROME=true # Launches Chrome ahead of time for faster render response
- CONNECTION_TIMEOUT=60000 # 60 seconds connection timeout
- KEEP_ALIVE=true
- DEMO_MODE=false
- DEBUG=false
# Limit resources to prevent runaway Chrome processes from locking your VPS
deploy:
resources:
limits:
memory: 2g
networks:
- monitor-network
volumes:
changedetection-data:
driver: local
networks:
monitor-network:
driver: bridge
Explaining Critical Variables:
PLAYWRIGHT_DRIVER_URL: Appending?stealth=trueto the WebSocket connection string instructs Browserless to inject anti-fingerprinting scripts. This hides headless Chrome characteristics (e.g., masking thenavigator.webdriverproperty) to evade detection.MAX_CONCURRENT_SESSIONS: Headless Chrome is notoriously resource-heavy. Setting a session ceiling ensures your VPS doesn't exhaust its CPU and RAM when multiple monitors execute at the same time.127.0.0.1:5000:5000: Binding ports to localhost prevents public access to your containers before you configure a secure reverse proxy with SSL certificate termination.
3. Step-by-Step Deployment Guide
Follow these terminal steps on your VPS to spin up the stack.
Step 1: Create the Directory and Write Compose File
sudo mkdir -p /opt/changedetection
cd /opt/changedetection
sudo nano docker-compose.yml
Paste the Docker Compose configuration provided above and save the file (Ctrl+O, Enter, Ctrl+X).
Step 2: Spin Up the Stack
sudo docker compose up -d
Verify that both containers are running properly:
sudo docker compose ps
Step 3: Configure Reverse Proxy (Caddy Example)
For public access over HTTPS, use a lightweight reverse proxy like Caddy. Install Caddy on your host and add the following config to /etc/caddy/Caddyfile:
monitor.yourdomain.com {
reverse_proxy localhost:5000
}
Reload Caddy to apply changes and automatically request an SSL certificate from Let's Encrypt:
sudo systemctl reload caddy
4. Configuring Playwright Browser Rendering
Once you log into the Changedetection.io dashboard, configure it to route scraper traffic through Playwright:
- Navigate to Settings > Fetch Method.
- Select Playwright (Chromium/Javascript) as the default fetcher instead of Basic fast Plaintext/HTTP Client.
- Click Save.
- Test the configuration by adding a dynamic JS page (e.g., a React dashboard or Twitter feed) and hitting Recheck.
When to use basic Fetcher vs. Playwright:
- Basic (cURL): Use for static blogs, raw RSS feeds, and REST APIs. It uses negligible system resources and executes instantly.
- Playwright: Use for modern SPAs, e.g., online retail stores (Amazon, BestBuy), dynamic charts, and pages requiring user actions (like cookie acceptance bypass).
5. Advanced Change Monitoring Techniques
Visual Filters (CSS / XPath selectors)
By default, Changedetection.io monitors the text content of the entire document. If a website changes its footer, sidebars, or CSRF tokens on every page load, it will trigger false positives.
To isolate changes: 1. Edit a watch and go to the Filters & Triggers tab. 2. In the CSS/XPath Filter field, input the selector targeting only the relevant content. - Example (Price Container): span.price-amount or //div[@id='product-price'] - Example (Article Body): article.post-entry
Stripping Dynamic Elements (Subtractions)
If you must monitor a large section but want to exclude dynamic elements like timestamp headers: 1. In the CSS/XPath Subtraction field, add the selectors of elements you want to ignore. - Example: .comment-section, .dynamic-timestamp, #ads-banner
Playwright Interactive Steps
Changedetection.io supports multi-step interactions prior to comparing changes. Navigate to the Playwright Steps tab of your watch configuration:
- Clicking cookie consent:
text click: button#accept-cookies wait: 2000 - Form Submission (Login):
text type: input#username, mysecretuser type: input#password, supersecurepwd click: button[type="submit"] wait: 5000
6. Notification Webhooks & Alert Routing
Changedetection.io integrates with Apprise, giving you out-of-the-box support for over 80 notification services.
Apprise Notification Strings
Go to Settings > Notifications to configure global alerts, or override them per watch. Examples of target strings:
- Discord:
discord://[WebhookID]/[WebhookToken] - Telegram:
tgrid://[BotToken]/[ChatID] - Gotify (Self-hosted):
gotify://[Host]/[Token]
Custom Webhook Payloads
If you are integrating Changedetection.io into an automated API workflow or CI/CD pipeline, configure a POST webhook:
- Use the notification string:
json://your-api.com/endpoint - Customize the JSON body in the Notification Body textarea:
{
"event": "page_changed",
"title": "{watch_title}",
"url": "{watch_url}",
"diff": "{diff}",
"timestamp": "{current_utc}"
}
7. Maintenance & Backups
All state, screenshot diffs, and watch definitions are stored inside the local volume mapped to /datastore in the changedetection container.
Automated Backups
Run a daily cron job to tarball the datastore directory and push it to secure external storage:
#!/bin/bash
BACKUP_DIR="/backup/changedetection"
mkdir -p "$BACKUP_DIR"
tar -czf "$BACKUP_DIR/changedetection_$(date +%F).tar.gz" -C /var/lib/docker/volumes/changedetection_changedetection-data/_data .
Updating the Stack
To update Changedetection.io and the Browserless container to their latest releases:
cd /opt/changedetection
sudo docker compose pull
sudo docker compose up -d --remove-orphans
sudo docker image prune -f