{
  "schema_version": 1,
  "generated_at": "2026-10-22T00:00:00.000Z",
  "canonical_url": "https://openlogs.fyi/tools/changedetection-io",
  "slug": "changedetection-io",
  "name": "changedetection.io",
  "tagline": "Watches web pages for changes and sends alerts when the content differs.",
  "replaces": {
    "summary": "Paid website change monitoring services, such as Visualping.",
    "products": [
      {
        "slug": "visualping",
        "name": "Visualping",
        "vendor": "Visualping",
        "url": "https://openlogs.fyi/alternatives/visualping"
      }
    ]
  },
  "stack": [
    {
      "kind": "language",
      "name": "Python"
    }
  ],
  "deployment_methods": [
    "docker_compose"
  ],
  "requirements": {
    "min_ram_mb": null,
    "min_cpu_cores": null,
    "source_url": null
  },
  "license": {
    "spdx": "Apache-2.0",
    "class": "osi",
    "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/LICENSE"
  },
  "business_model": {
    "value": "unknown",
    "notes": "The README at the pinned commit does not state a business model, so it stays unknown.",
    "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/README.md",
    "checked_at": "2026-10-22"
  },
  "difficulty": {
    "value": "easy",
    "reason": "1 service, 1 volume mount, no env values to set, no elevated host access. Heuristic score 0 of 11: easy."
  },
  "repository": {
    "owner": "dgtlmoon",
    "name": "changedetection.io",
    "url": "https://github.com/dgtlmoon/changedetection.io"
  },
  "compose_check": {
    "status": "config_ok",
    "validated_at": "2026-10-22",
    "summary": "config_ok on 2026-10-22"
  },
  "recipe": {
    "version": 1,
    "source_path": "docker-compose.yml",
    "source_repo": "dgtlmoon/changedetection.io",
    "source_commit_sha": "be09f73c3af1bbc698d19a532ef6d3c9987e6370",
    "source_kind": "app_repo",
    "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/docker-compose.yml"
  },
  "install_steps": [
    {
      "order": 1,
      "kind": "prerequisite",
      "language": "text",
      "label": "Docker with the Compose plugin",
      "body": "A host with Docker and the Docker Compose plugin. This entry runs from a compose file.",
      "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/docker-compose.yml",
      "validation_status": "unvalidated"
    },
    {
      "order": 2,
      "kind": "compose",
      "language": "yaml",
      "label": "Save the compose file as docker-compose.yml",
      "body": "services:\n    changedetection:\n      image: ghcr.io/dgtlmoon/changedetection.io\n      container_name: changedetection\n      hostname: changedetection\n      volumes:\n        - changedetection-data:/datastore\n# Configurable proxy list support, see https://github.com/dgtlmoon/changedetection.io/wiki/Proxy-configuration#proxy-list-support\n#        - ./proxies.json:/datastore/proxies.json\n\n  #    environment:\n  #        Default listening port, can also be changed with the -p option (not to be confused with ports: below)\n  #      - PORT=5000\n  #\n  #        Log levels are in descending order. (TRACE is the most detailed one)\n  #        Log output levels: TRACE, DEBUG(default), INFO, SUCCESS, WARNING, ERROR, CRITICAL\n  #      - LOGGER_LEVEL=TRACE\n  #\n  #        Plugins! See https://changedetection.io/plugins for more plugins.\n  #        Install additional Python packages (processor plugins, etc.)\n  #        Example: Install the OSINT reconnaissance processor plugin\n  #      - EXTRA_PACKAGES=changedetection.io-osint-processor\n  #        Multiple packages can be installed by separating with spaces:\n  #      - EXTRA_PACKAGES=changedetection.io-osint-processor another-plugin\n  #\n  #\n  #       Uncomment below and the \"sockpuppetbrowser\" to use a real Chrome browser (It uses the \"playwright\" protocol)\n  #      - PLAYWRIGHT_DRIVER_URL=ws://browser-sockpuppet-chrome:3000\n  #      # Disable when the remote CDP implementation does not support `Page.setBypassCSP` - like with Obscura browser.\n  #      - PLAYWRIGHT_BYPASS_CSP=false\n  #\n  #\n  #       Alternative WebDriver/selenium URL, do not use \"'s or 's! (old, deprecated, does not support screenshots very well, Can't handle custom headers etc)\n  #      - WEBDRIVER_URL=http://browser-selenium-chrome:4444/wd/hub\n  #\n  #       WebDriver proxy settings webdriver_proxyType, webdriver_ftpProxy, webdriver_noProxy,\n  #                                webdriver_proxyAutoconfigUrl, webdriver_autodetect,\n  #                                webdriver_socksProxy, webdriver_socksUsername, webdriver_socksVersion, webdriver_socksPassword\n  #\n  #             https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.proxy\n  #\n  #\n  #       Playwright proxy settings playwright_proxy_server, playwright_proxy_bypass, playwright_proxy_username, playwright_proxy_password\n  #\n  #             https://playwright.dev/python/docs/api/class-browsertype#browser-type-launch-option-proxy\n  #\n  #        Plain requests - proxy support example.\n  #      - HTTP_PROXY=socks5h://10.10.1.10:1080\n  #      - HTTPS_PROXY=socks5h://10.10.1.10:1080\n  #\n  #        An exclude list (useful for notification URLs above) can be specified by with\n  #      - NO_PROXY=\"localhost,192.168.0.0/24\"\n  #\n  #        Base URL of your changedetection.io install (Added to the notification alert)\n  #      - BASE_URL=https://mysite.com\n  #        Respect proxy_pass type settings, `proxy_set_header Host \"localhost\";` and `proxy_set_header X-Forwarded-Prefix /app;`\n  #        More here https://github.com/dgtlmoon/changedetection.io/wiki/Running-changedetection.io-behind-a-reverse-proxy\n  #      - USE_X_SETTINGS=1\n  #\n  #        Hides the `Referer` header so that monitored websites can't see the changedetection.io hostname.\n  #      - HIDE_REFERER=true\n  #        \n  #        Default number of parallel/concurrent fetchers\n  #      - FETCH_WORKERS=10\n  #\n  #        Absolute minimum seconds to recheck, overrides any watch minimum, change to 0 to disable\n  #      - MINIMUM_SECONDS_RECHECK_TIME=3\n  #\n  #        Cap the total number of watches this instance will hold - adding more (UI, API, import)\n  #        is refused until one is deleted. Unset means unlimited.\n  #      - PAGE_WATCH_LIMIT=100\n  #\n  #        If you want to watch local files file:///path/to/file.txt (careful! security implications!)\n  #      - ALLOW_FILE_URI=False\n  #\n  #        Off by default - Private lan, local-only, testing/documentation, multicast, protocol infrastructure, and ranges intentionally not usable as normal public unicast IPs\n  #      - ALLOW_IANA_RESTRICTED_ADDRESSES=true\n  #\n  #        For complete privacy if you don't want to use the 'check version' / telemetry service\n  #      - DISABLE_VERSION_CHECK=true\n  #\n  #        Disable all LLM / AI features, prompts etc\n  #      - LLM_FEATURES_DISABLED=true\n  #\n  #        How much of the page text the AI reads when finding the price/stock, default 15000 characters.\n  #        Raise it if the price is missed (some shops put it far down the page).\n  #        Using a local model (Ollama)? It may only read the first part unless you raise its context size\n  #        (num_ctx) to about 8192 or more, otherwise it can miss the price.\n  #        In Ollama: run `ollama run <model>` then `/set parameter num_ctx 8192`\n  #      - LLM_RESTOCK_MAX_CONTENT_CHARS=15000\n  #\n  #        Fetch the latest LLM model pricing (used for the estimated cost counter) from GitHub, default false.\n  #        When false the pricing list that ships with this version is used, so no outbound request is made. (Off by default for privacy)\n  #      - LITELLM_FETCH_PRICING_FROM_GITHUB=false\n  #\n  #        A valid timezone name to run as (for scheduling watch checking) see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\n  #      - TZ=America/Los_Angeles\n  #\n  #        Text processing locale, en_US.UTF-8 used by default unless defined as something else here, UTF-8 should cover 99.99% of cases.\n  #      - LC_ALL=en_US.UTF-8\n  #\n  #        Maximum height of screenshots, default is 20000 px, screenshots will be clipped to this if exceeded.\n  #        RAM usage will be higher if you increase this.\n  #      - SCREENSHOT_MAX_HEIGHT=20000\n  #\n  #        HTTPS SSL Mode for webserver, unset both of these, you may need to volume mount these files also.\n  #        ./cert.pem:/app/cert.pem and ./privkey.pem:/app/privkey.pem\n  #      - SSL_CERT_FILE=cert.pem\n  #      - SSL_PRIVKEY_FILE=privkey.pem\n  #\n  #        LISTEN_HOST / \"host\", Same as -h\n  #      - LISTEN_HOST=::\n  #      - LISTEN_HOST=0.0.0.0\n\n  \n      # Comment out ports: when using behind a reverse proxy , enable networks: etc.\n      # Mac users! Use \"127.0.0.1:5050:5000\" (port 5050) so theres no conflict with Airplay etc. (https://github.com/dgtlmoon/changedetection.io/issues/3401)\n      ports:\n        - 127.0.0.1:5000:5000\n      restart: unless-stopped\n\n     # Used for fetching pages via WebDriver+Chrome where you need Javascript support.\n     # Now working on arm64 (needs testing on rPi - tested on Oracle ARM instance)\n     # replace image with seleniarm/standalone-chromium:4.0.0-20211213\n     \n     # If WEBDRIVER or PLAYWRIGHT are enabled, changedetection container depends on that\n     # and must wait before starting (substitute \"browser-chrome\" with \"playwright-chrome\" if last one is used)\n#      depends_on:\n#          browser-sockpuppet-chrome:\n#              condition: service_started\n\n\n     # Sockpuppetbrowser is basically chrome wrapped in an API for allowing fast fetching of web-pages.\n     # RECOMMENDED FOR FETCHING PAGES WITH CHROME, be sure to enable the \"PLAYWRIGHT_DRIVER_URL\" env variable in the main changedetection container\n#    browser-sockpuppet-chrome:\n#        hostname: browser-sockpuppet-chrome\n#        image: dgtlmoon/sockpuppetbrowser:latest\n#        cap_add:\n#            - SYS_ADMIN\n## SYS_ADMIN might be too much, but it can be needed on your platform https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#running-puppeteer-on-gitlabci\n#        restart: unless-stopped\n#        environment:\n#            - SCREEN_WIDTH=1920\n#            - SCREEN_HEIGHT=1024\n#            - SCREEN_DEPTH=16\n#            - MAX_CONCURRENT_CHROME_PROCESSES=10\n\n     # Used for fetching pages via Playwright+Chrome where you need Javascript support.\n     # Note: Works well but is deprecated, does not fetch full page screenshots (doesnt work with Visual Selector)\n     #       Does not report status codes (200, 404, 403) and other issues\n#    browser-selenium-chrome:\n#        hostname: browser-selenium-chrome\n#        image: selenium/standalone-chrome:4\n#        environment:\n#            - VNC_NO_PASSWORD=1\n#            - SCREEN_WIDTH=1920\n#            - SCREEN_HEIGHT=1080\n#            - SCREEN_DEPTH=24\n#          CHROME_OPTIONS: |\n#            --window-size=1280,1024\n#            --headless\n#            --disable-gpu\n#        volumes:\n#            # Workaround to avoid the browser crashing inside a docker container\n#            # See https://github.com/SeleniumHQ/docker-selenium#quick-start\n#            - /dev/shm:/dev/shm\n#        restart: unless-stopped\n\nvolumes:\n  changedetection-data:\n",
      "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/docker-compose.yml",
      "validation_status": "config_ok"
    },
    {
      "order": 3,
      "kind": "shell",
      "language": "bash",
      "label": "Start it",
      "body": "docker compose up -d",
      "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/docker-compose.yml",
      "validation_status": "unvalidated"
    },
    {
      "order": 4,
      "kind": "verify",
      "language": "text",
      "label": "Open the app",
      "body": "Open http://localhost:5000. The compose file publishes host port 5000 for the changedetection service.",
      "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/docker-compose.yml",
      "validation_status": "unvalidated"
    }
  ],
  "notes": [
    {
      "kind": "gotcha",
      "title": "Some images use the latest tag or no tag",
      "body": "Images without a pinned version: changedetection: ghcr.io/dgtlmoon/changedetection.io (no tag). A later pull can get a different version.",
      "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/docker-compose.yml",
      "checked_at": "2026-10-22"
    },
    {
      "kind": "gotcha",
      "title": "The compose file publishes host ports",
      "body": "Host ports: 127.0.0.1:5000 (changedetection).",
      "source_url": "https://github.com/dgtlmoon/changedetection.io/blob/be09f73c3af1bbc698d19a532ef6d3c9987e6370/docker-compose.yml",
      "checked_at": "2026-10-22"
    }
  ],
  "signals": {
    "captured_at": "2026-10-22",
    "stars": 35202,
    "forks": 2174,
    "open_issues": 404,
    "last_push": "2026-10-19",
    "days_since_push": 2,
    "latest_release": "0.60.9",
    "latest_release_date": "2026-10-12",
    "days_since_release": 9
  },
  "links": {
    "html": "https://openlogs.fyi/tools/changedetection-io",
    "markdown": "https://openlogs.fyi/tools/changedetection-io.md",
    "json": "https://openlogs.fyi/tools/changedetection-io.json"
  },
  "updated_at": "2026-10-22"
}
