Self-hosted service
dgtlmoon/changedetection.io avatar
dgtlmoon/changedetection.io

changedetection.io: self-hosted website change monitoring with Docker

Best and simplest tool for website change detection, web page monitoring, and website change alerts. Perfect for tracking content changes, price drops, restock alerts, and website defacement monitoring:all for free or enjoy our SaaS plan!

34,670 stars2,108 forksPythonApache-2.0

At a glance

What is it?
changedetection.io is a Python and Flask application that watches web pages, PDFs and JSON endpoints and pushes alerts through Apprise. This review covers the Docker install path, the filter chain, the Playwright requirement for interactive pages, and the licence split.
Who is it for?
Adopt changedetection.io if you need to watch many URLs on your own hardware, want the diff stored locally, and are willing to run a second container when a page needs JavaScript. Skip it if you need a managed service with proxies and no operations work, or if your monitoring rules are already expressed as code in something like Prometheus blackbox_exporter.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What changedetection.io actually watches

The core job is narrow: fetch a URL on a schedule, reduce the response to comparable text, compare it against the last stored version, and fire a notification when the two differ. The README lists the intended audiences explicitly, and they are not all the same shape of problem. Price monitoring and restock alerts need structured extraction from product pages. Defacement monitoring and PCI compliance checks want the raw HTML source compared with nothing stripped. Government and regulatory pages are usually static HTML where a plain fetch is enough. PDF monitoring is a fourth case, and the README says the tool tracks both the text inside a PDF and its filesize and checksums, which matters because a re-rendered PDF can change bytes without changing a word.

The people this fits are the ones who already run a server and object to paying per-URL. The README makes that argument directly, noting the case of a sensitive list of URLs where you do not want to use paid alternatives, with the aside that you are the product. That is a positioning statement, not a technical one, but it explains the design: everything, including the history of every diff, lives in a local datastore directory rather than on someone else's infrastructure. The hosted plan at changedetection.io exists for people who do not want to run the container, and the README is upfront that some features, including the Visual Selector and the AI change detection rules, are tied to that subscription as of June 2026.

The fetch, filter and diff pipeline

Architecturally this is a Flask application. The dependency list confirms the stack: flask, flask-login, flask-socketio for live updates in the browser, flask-restful for the API, flask_wtf for forms, and orjson for serialization. The comparison engine is diff_match_patch, the same algorithm family Google's diff libraries use, which is why the UI can show changes at word, line or character granularity rather than dumping two blobs of HTML.

The pipeline has four stages. A fetcher retrieves the page. A set of filters reduces it. The diff engine compares the result with the stored previous version. A notifier sends the alert. The filters are where most of the configuration effort goes, and the README lists the vocabulary: trigger on text, remove text by selector, ignore text, extract text, all of which accept regular expressions. Element targeting uses xPath 1, xPath 2 or CSS selectors, and JSON responses can be narrowed with JSONPath or jq. That last detail has a platform consequence the requirements file states plainly: jq is not available on Windows and must be installed manually, so JSON filtering on a Windows host is a different setup than on Linux.

Fetching is the part that decides whether the tool works on a given site. There are two modes. The fast mode does a plain HTTP request with no JavaScript execution. The Chrome mode drives a real browser over the Playwright protocol or, in a deprecated path, WebDriver. The docker-compose file shows how the Playwright mode is wired: you uncomment a sockpuppetbrowser service and set PLAYWRIGHT_DRIVER_URL to ws://browser-sockpuppet-chrome:3000. Browser Steps, which fills text boxes and clicks buttons before detection runs, requires Playwright to be enabled. Visual Selector does too. So the interactive features are not a configuration toggle on the main container; they are a second container plus an environment variable.

Installing changedetection.io with Docker Compose

The repository ships a docker-compose.yml that pulls ghcr.io/dgtlmoon/changedetection.io and mounts a named volume at /datastore. That volume is the whole state of the application: watch definitions, snapshots, and history. The minimal service definition is short.

yaml
services:
    changedetection:
      image: ghcr.io/dgtlmoon/changedetection.io
      container_name: changedetection
      hostname: changedetection
      volumes:
        - changedetection-data:/datastore

Bring it up with docker compose up -d and the web interface listens on port 5000 by default. The compose file's comments note that the default listening port can also be changed with the -p option, and that the internal port is set through the PORT environment variable. Two other environment variables are documented in the same block: LOGGER_LEVEL, which accepts TRACE, DEBUG, INFO, SUCCESS, WARNING, ERROR or CRITICAL, and EXTRA_PACKAGES, which installs additional Python packages at startup. Multiple packages are separated by spaces.

bash
EXTRA_PACKAGES=changedetection.io-osint-processor

That is the plugin mechanism, and it is worth being precise about it: plugins are Python packages installed into the container, not a marketplace you browse inside the UI. The compose comments point at changedetection.io/plugins for the list. There is also a pip path. setup.py declares a console script entry point named changedetection.io, and README-pip.md is the long description used for the package, so the application can be installed and launched from Python rather than Docker. The pip route shifts the dependency management onto you, including the cryptography pin and the Playwright exclusion described in the Dockerfile.

For a first real watch, the workflow is: add a URL, let the first fetch establish the baseline, then edit the watch to add filters. Nothing is compared on the first fetch because there is no previous version to compare against. If you are watching a product page, the README describes a dedicated option, Re-stock and Price detection for single product pages, which extracts metadata from the HTML and exposes upper and lower price bounds and a price change percentage threshold. That is a configuration panel rather than a filter you write by hand.

Where the JavaScript fetcher changes the deployment

The single largest operational surprise is that a plain Docker install does not include a browser. The Dockerfile installs playwright as a separate pip step and wraps it in a fallback that echoes a warning if the install fails, with a comment explaining the package was kept out of requirements.txt so that arm/v6 and arm/v7 builds do not break. The image is built for multiple architectures, and the browser path is the one that gets sacrificed on the smallest ones.

On top of that, the Playwright fetcher is documented as part of the subscription service, described as included with the hosted plan. The compose file does show how to point the main container at a sockpuppetbrowser instance, so the mechanism exists in the open source deployment, but the README's own framing of the Visual Selector and Browser Steps ties them to the paid offering. Anyone evaluating the free path should read that as: budget for a second container and for the possibility that the polished selector tooling is not what you get. If your target pages render content server-side, none of this matters and the fast fetcher is enough. If they do not, the fast fetcher will happily report a stable page that never changes, because the content you care about is assembled in the browser.

Notifications, licensing and the upgrade path

Alerts go through Apprise, pinned at 1.13.1 in requirements.txt. That pin is doing real work: Apprise is the layer that reaches Discord, email, Slack, Telegram, webhooks and MQTT, and the README also mentions generating RSS feeds from changes. The requirements file carries a comment about paho-mqtt excluding the 2.0.x series because of an upstream issue, and another explaining that dnspython is no longer pinned now that eventlet has been removed. Those comments are unusually informative for a dependency file and tell you the maintainers have been through a broker-resolution problem before.

Licensing is split. The repository contains both LICENSE and COMMERCIAL_LICENCE.md, and setup.py declares the package name changedetection.io. The README's own license shield points at LICENSE.md. The practical reading is that the open source core is Apache-2.0 and a separate commercial licence exists for something, most likely the hosted service or commercial redistribution. The file is present in the repository root, so the terms are readable before you commit to anything. If you plan to resell monitoring as a service, read COMMERCIAL_LICENCE.md rather than assuming Apache-2.0 covers it. That is not legal advice; it is a pointer to the document that would answer the question.

Upgrade cost is low if you use the image. The releases listed are 0.55.8 on 2026-07-13, 0.55.7 on 2026-05-25 and 0.55.6 on 2026-05-25, and the last push to master was on 2026-07-13. Pulling a new tag and restarting the container is the whole procedure, and the datastore volume survives it. The risk sits in the environment variables and the extra packages, not the application code. A pinned EXTRA_PACKAGES value is the thing most likely to break across a jump, because it installs from PyPI at container start and is not version-locked by the image.

Alternatives and when this is the wrong tool

The obvious comparison is Visualping, which the search data itself raises. The difference is architectural, not cosmetic. Visualping is a hosted service: you point it at a URL and it does the fetching, rendering and storing on its infrastructure, and you pay per volume. changedetection.io inverts that. You supply the compute, the network egress and the storage, and in exchange the watch history never leaves your datastore volume. Neither model is strictly better. A hosted service can route through residential proxies and absorb a site blocking its crawler; a self-hosted instance on a single IP gets blocked and stays blocked until you configure a proxy. The README links to a proxy-per-watch wiki page and to Bright Data, which tells you the maintainers consider proxy configuration a normal part of operation rather than an edge case.

Against something like Prometheus blackbox_exporter the split is different again. blackbox_exporter checks reachability, status codes and TLS certificate expiry, and its rules live in a config file under version control. It does not diff page content, and it does not try to. changedetection.io is for content, not availability. If your actual question is whether a service is up, this tool is the wrong shape and will generate diffs you do not care about.

The case where changedetection.io is genuinely the wrong tool is a site that requires authentication with a real login flow, heavy client-side rendering, and anti-bot protection, all at once. Browser Steps can fill a form and click a button, but the README does not document a credential-rotation or session-refresh strategy, and there is no mention of captcha handling. For that class of target you are buying a proxy and browser service either way, at which point the self-hosted argument weakens considerably.

Editorial conclusion

Adopt changedetection.io if you need to watch many URLs on your own hardware, want the diff stored locally, and are willing to run a second container when a page needs JavaScript. Skip it if you need a managed service with proxies and no operations work, or if your monitoring rules are already expressed as code in something like Prometheus blackbox_exporter. Before rolling it out, open the /docs API page on your build and confirm the endpoints you plan to call exist there, and read COMMERCIAL_LICENCE.md if you intend to resell the service.

Frequently asked questions

Is changedetection.io free?

The open source application is available under Apache-2.0 and can be self-hosted from the ghcr.io image or installed from pip. The README also offers a hosted subscription at $8.99 per month, and states that some features, including the Visual Selector and AI change detection rules, are available in that subscription service.

How do I install changedetection.io?

The repository ships a docker-compose.yml that pulls ghcr.io/dgtlmoon/changedetection.io and mounts a volume at /datastore. Run docker compose up -d and the interface is available on port 5000 by default. There is also a pip installation path, with a console script entry point named changedetection.io declared in setup.py.

How do I use changedetection.io to watch a page?

Add a URL as a watch and let the first fetch establish the baseline, since nothing is compared until a previous version exists. Then add filters such as trigger on text, remove text by selector, or ignore text, using CSS selectors, xPath 1, xPath 2, JSONPath or jq depending on the response type. For product pages the README describes a Re-stock and Price detection option that extracts page metadata and lets you set price bounds and a percentage threshold.

Is changedetection.io safe to run?

It is a self-hosted Flask application, so the data it collects stays in the datastore volume you mount rather than on a third party's servers. The README does not document a security audit, and the repository includes a separate COMMERCIAL_LICENCE.md alongside the Apache-2.0 LICENSE, so review both before deploying it somewhere untrusted.

What is changedetection.io?

It is a self-hosted website change detection and monitoring service written in Python on Flask. It fetches pages on a schedule, compares the reduced text against the stored previous version, and sends alerts through Apprise to destinations such as Discord, email, Slack, Telegram, webhooks and MQTT.

Is there a free tool that can detect website changes?

changedetection.io is one, and its README positions the self-hosted deployment as the free alternative to paid services. You supply the host and the datastore volume, and the application itself is Apache-2.0 licensed. Some features, including the Visual Selector and AI change detection rules, are documented as part of the hosted subscription instead.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dgtlmoon-changedetection-io.svg)](https://hysenlabs.com/projects/dgtlmoon-changedetection-io)