On this page
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:
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.
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 (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.
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:
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:
# public ntfy.sh, dedicated topic:
ntfy://homelab-releases
# or a self-hosted ntfy server:
ntfys://ntfy.homelab.lan/homelab-releases
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:
- Paperless-ngx: OCR Every Document You Own, Searchable — the previous post: make your documents findable.
- SMART Disk-Health Trending for Your Whole Fleet — the series finale: watch the disks under everything.
- Give Your Local AI Private Web Search With SearXNG — where the series started: your own private search engine.
- Uptime Kuma: Simple Homelab Monitoring — the friendly status-page companion to a change watcher.
- What Is Prometheus? — the metrics stack behind the dead-man probe.
- Tailscale Subnet Router for Your Homelab — reach an unauthenticated tool safely from anywhere.
- Create Your First Proxmox LXC Container — where the watcher lives in this build.
Comments
Comments are powered by GitHub Discussions — sign in with a GitHub account to join the conversation.