Skip to content

changedetection.io

Self-Hosted Website Change Detection

changedetection.io is a self-hosted website change detection and monitoring tool. It watches web pages for content changes and sends notifications, with support for JavaScript-rendered pages via Playwright+Chrome.

Why Choose changedetection.io

  • Privacy first - monitored URLs and change history stay on your own server
  • JavaScript support - fetch pages rendered with JavaScript via Playwright+Chrome
  • Flexible notifications - supports many notification backends (email, Slack, Telegram, etc.)
  • Visual selector - pick exactly which part of a page to monitor
  • Filters and triggers - ignore noise with CSS/XPath selectors, text filters, and trigger conditions

Install

Infrastructure Configuration

Infrastructure as Code

The canonical configuration is maintained at Benoit/OpenTofu.

The changedetection.io VM is provisioned with OpenTofu. Two extra block volumes are attached: one for Docker data and one for /opt where changedetection.io lives.

OpenTofu configuration
resource "incus_storage_volume" "changedetection_var_lib_docker" {
  name         = "changedetection_var_lib_docker"
  pool         = incus_storage_pool.default.name
  content_type = "block"
  config = {
    "size" = "50GiB"
  }
}

resource "incus_storage_volume" "changedetection_opt" {
  name         = "changedetection_opt"
  pool         = incus_storage_pool.default.name
  content_type = "block"
  config = {
    "size" = "10GiB"
  }
}

resource "incus_instance" "changedetection" {
  name  = "changedetection"
  image = "images:ubuntu/24.04"
  type  = "virtual-machine"

  config = {
    "limits.cpu"    = 2
    "limits.memory" = "4GiB"
  }

  device {
    name = "root"
    type = "disk"
    properties = {
      size = "25GiB"
      path = "/"
      pool = incus_storage_pool.default.name
    }
  }

  device {
    name = "var_lib_docker"
    type = "disk"
    properties = {
      # Mount manually inside the VM: path = "/var/lib/docker"
      source = incus_storage_volume.changedetection_var_lib_docker.name
      pool   = incus_storage_pool.default.name
    }
  }

  device {
    name = "opt"
    type = "disk"
    properties = {
      # Mount manually inside the VM: path = "/opt"
      source = incus_storage_volume.changedetection_opt.name
      pool   = incus_storage_pool.default.name
    }
  }
}

Manual mount required

The var_lib_docker and opt block volumes are attached to the VM but not auto-mounted. After the VM first boots, format and mount them manually before installing Docker or cloning changedetection.io.

Deploy Infrastructure

Apply OpenTofu configuration
tofu apply

Inside the VM: Format and Mount Volumes

After the first boot, identify the two attached block devices and set them up:

Format and mount the volumes

Format and mount block volumes
mkfs.ext4 /dev/sdb && mkfs.ext4 /dev/sdc
mkdir -p /var/lib/docker /opt
mount /dev/sdb /opt
mount /dev/sdc /var/lib/docker

Persist mounts across reboots

Add fstab entries
echo '/dev/sdb /opt ext4 defaults 0 2' >> /etc/fstab
echo '/dev/sdc /var/lib/docker ext4 defaults 0 2' >> /etc/fstab

Inside the VM: Docker and changedetection.io

Install Docker

Install Docker via official convenience script
curl -fsSL https://get.docker.com | sh

Clone the changedetection.io repository

Clone a specific version into /opt
git clone --branch 0.54.6 https://github.com/dgtlmoon/changedetection.io.git /opt/changedetection

Enable Playwright+Chrome

Edit docker-compose.yml to uncomment the Playwright browser service and its dependency:

docker-compose.yml โ€” enable Playwright+Chrome
services:
  changedetection:
    image: ghcr.io/dgtlmoon/changedetection.io
    container_name: changedetection
    hostname: changedetection
    volumes:
      - changedetection-data:/datastore
    environment:
      - PLAYWRIGHT_DRIVER_URL=ws://browser-sockpuppet-chrome:3000
    ports:
      - 0.0.0.0:5000:5000
      - "[::]:5000:5000"
    restart: unless-stopped
    depends_on:
      browser-sockpuppet-chrome:
        condition: service_started

  browser-sockpuppet-chrome:
    hostname: browser-sockpuppet-chrome
    image: dgtlmoon/sockpuppetbrowser:latest
    cap_add:
      - SYS_ADMIN
    restart: unless-stopped
    environment:
      - SCREEN_WIDTH=1920
      - SCREEN_HEIGHT=1024
      - SCREEN_DEPTH=16
      - MAX_CONCURRENT_CHROME_PROCESSES=10

volumes:
  changedetection-data:

Start changedetection.io

Start all containers
cd /opt/changedetection
docker compose up -d

Related Documentation: