Watch Any Web Page for Changes With changedetection.io

Self-host changedetection.io to watch release pages, security advisories, and prices — and push a phone alert only when a page actually changes.

On this page
  1. What changedetection.io is
  2. Deploy it
  3. The real skill: pick endpoints a browser doesn’t need
  4. The RSS trap that alerts you forever
  5. Push it to your phone with ntfy
  6. Watch the watcher
  7. What’s next

There’s a specific flavor of guilt I know well: the tab I keep open to a project’s releases page, meaning to check whether the security fix shipped yet. Or the vendor advisory page I should be watching. Or the price of the thing I want, which I refresh at random and always seem to miss the drop on. I keep meaning to check these, and I never do — because “remember to manually check a web page on a schedule” is a job humans are catastrophically bad at.

So I stopped doing it. changedetection.io is a self-hosted watcher: you give it a page, it polls it on a schedule, and it pings your phone only when something actually changes. This is the fourth stop in the Self-Host the Apps You Actually Use series, and it’s the one that turned a nagging chore into something I genuinely never think about anymore.

Here’s the loop it runs so you don’t have to:

Poll, diff, and only bother you when it mattersWatcherfetch every 6hthe pagechanged?no → stay quietntfyyour phoneNine checks out of ten it finds nothing and says nothing. The tenth, you get a ping.
First: make these values your own

The values below are examples. Replace 10.0.0.60 with your changedetection host’s real IP, and choose your own ntfy topic name in place of homelab-releases — pick something unguessable, since anyone who knows a public ntfy topic name can read it. If a value looks specific to one machine, it’s a placeholder to change — not a literal to copy.


What changedetection.io is

changedetection.io is, at heart, a very disciplined robot that reloads web pages and compares them to last time. You add a watch — a URL plus how often to check it — and it stores a snapshot. On each check it fetches the page again, diffs it against the stored version, and if the parts you care about changed, it fires a notification. It’s open source, it’s light, and it’s genuinely one of those tools that pays for its keep the first week.

The classic uses are exactly the chores you keep forgetting: software release pages, security advisories, product prices, restock alerts, and terms-of-service or policy pages. Anything that lives at a stable URL and updates on its own clock is a candidate.


Deploy it

changedetection.io offers both a Docker install and a native pip install (it needs Python 3.10+). I run it natively in a small Proxmox LXC under systemd, but the Docker route is a single command if you’d rather.

1Install changedetection.io10 min

The native install is a pip install into a virtualenv, run under a dedicated service user. A 2-core, 1 GB container is plenty if you stick to browserless watches (more on that next).

Native install (pip), or the Docker one-liner

# Native (Python 3.10+), pinned to a known release:
pip install changedetection.io==0.55.8
changedetection.io -d /var/lib/changedetection/data -p 5000

# Or Docker:
docker run -d --restart always -p 127.0.0.1:5000:5000 -v datastore-volume:/datastore --name changedetection dgtlmoon/changedetection.io

Pin the version deliberately (like any self-hosted service) and bump it on purpose after reading the changelog. Open the UI on port 5000 to add your first watch.

It ships with no authentication

Out of the box, anyone who can reach the web UI can see and edit your watches. Keep it on a trusted LAN or reach it over Tailscale — never expose it straight to the internet. If you must, put an authenticating reverse proxy in front.


The real skill: pick endpoints a browser doesn’t need

Here’s the trick that keeps this running happily on a tiny container. changedetection.io can drive a full headless browser to render JavaScript-heavy pages — but that’s heavy, and you rarely need it. If the information you want is exposed as a JSON API, an RSS/Atom feed, or plain static HTML, you can fetch and parse it directly with no browser at all. It supports XPath, JSONPath, jq, and CSS filters under the Filters & Triggers tab, so you can pinpoint exactly the value that matters and ignore the churn around it.

That framing changes how you choose what URL to watch. Instead of watching a vendor’s pretty download page (JavaScript, ads, a rotating banner — all noise), watch the JSON or feed behind it. Here are the kinds of targets I reach for:

What you want Watch this kind of URL Filter
A project’s latest release Its releases JSON/Atom or GitHub releases API json:$.tag_name
A specific product version The vendor’s downloads JSON API json:$.<path.to.version>
Forum/announcement posts The section’s RSS feed xpath://item/title
A plain content page The static HTML page a CSS/XPath selector for the region

Every one of those is parseable without a browser, which is why five real watches sit comfortably on a 1 GB box.

The RSS trap that alerts you forever

The first time I watched an RSS feed unfiltered, my phone buzzed on every single check even though nothing new had been posted. The culprit: most feeds include a lastBuildDate (or similar) timestamp that’s regenerated every time the feed is served. To changedetection.io, that timestamp changing is a change. The fix is to filter down to just the part you care about — for a feed, an XPath selecting the item titles:

Filter the feed, or it cries wolf every checkwatch whole feedlastBuildDate includedfires EVERY checkalert fatiguexpath://item/titletitles onlyfires on real posts onlysignal, not noise

Push it to your phone with ntfy

Notifications run through Apprise, a library that speaks to dozens of services. My favorite for this is ntfy — dead simple push notifications you subscribe to by topic in a phone app. In a watch’s Notifications list, add an Apprise ntfy URL:

Apprise ntfy notification URL

# public ntfy.sh, dedicated topic:
ntfy://homelab-releases

# or a self-hosted ntfy server:
ntfys://ntfy.homelab.lan/homelab-releases
Give releases their own topic

Don’t reuse the topic your urgent alerts (a down service, a failed backup) go to. Release notices are interesting, not urgent, and mixing them trains you to ignore the topic that actually matters. A separate homelab-releases topic keeps the monitoring pager channel meaningful. Pick an unguessable topic name, too — public ntfy topics are readable by anyone who knows the name.

To be sure it works end to end, I add a throwaway watch on a page that changes on every request, force a recheck, and confirm the ping lands on my phone. Then I delete the test watch. Proving the whole chain — detect → Apprise → ntfy → phone — beats assuming any one link works.


Watch the watcher

There’s a delicious irony here: a tool whose entire job is to notice things can itself die quietly and stop noticing anything, and you’d never know. So I point a black-box uptime probe at its web UI and alert if it stops answering — a dead-man switch, so a dead watcher pages me instead of failing silent. The companion playbook has the full deploy, five example watches, and the probe.


What’s next

That’s four apps that make the homelab genuinely more useful — private search, self-tagging bookmarks, an OCR’d document archive, and a tireless page-watcher. To close the series, we go one layer down and protect the thing all of it runs on: SMART disk-health trending, so a dying drive warns you weeks ahead instead of taking your data with it.


Related posts:

Comments

Comments are powered by GitHub Discussions — sign in with a GitHub account to join the conversation.