Upgrading from urlwatch
webchanges reads your urlwatch jobs and configuration files as they are, so you keep every job you have built and gain clearer reports, AI summaries, image and structured-data diffs, and an HTTP client that gets past bot walls. It began as a fork of urlwatch 2.21 and has been developed independently since 2020, while staying compatible with urlwatch’s files: most setups need no edits at all.
For a feature-by-feature table, see the webchanges vs urlwatch comparison.
Why switch
Reports you can read at a glance
HTML reports keep the page’s formatting (bold, italics, underlining, headers, bulleted lists and indentation) and its links stay clickable.
Added and deleted lines are marked with color and strikethrough, readable in dark mode and in email clients that strip stylesheets, such as Gmail.
Long lines wrap instead of being cut off.
The table differ shows changes side by side, and the wdiff differ highlights the words that changed within a line.
The
telegramreporter keeps links, bold, italics, underlining and strikethrough.
Changes worth being told about
The ai_google differ summarizes a long diff (a contract, a policy, terms of service) in a paragraph of plain language, using Google’s Gemini.
The image differ watches images and reports an image with the differences highlighted.
The deepdiff differ compares JSON, YAML and XML element by element, so that reordered list items, reformatting or noise in the last decimal don’t raise false alarms.
additions_only reports only what was added, such as new items in a list, and
deletions_onlyonly what was removed.
Sites that block urlwatch
Choose the HTTP client per job with http_client:
httpx(with HTTP/2),requests, orcurl_cffi, which presents the TLS fingerprint of a real browser to get past Cloudflare, Akamai and similar bot walls.Browser jobs run Chrome, Edge, Firefox or WebKit through Playwright, can wait for a URL, a selector or a JavaScript condition, block images and other resources, and can attach to a browser that is already running (connect_over_cdp).
same_site_delay spaces out jobs that hit the same site, to stay clear of rate limits.
Fewer false alarms
empty_as_error treats an empty response as a transient error instead of reporting the page’s content disappearing and then reappearing.
suppress_repeated_errors reports an error once, not on every run, and suppress_error_ended skips the report that an error has ended when the content is unchanged.
ignore_connection_errors,ignore_timeout_errors,ignore_http_error_codesand the otherignore_*directives also work for browser jobs.
Snapshots you can trust
Snapshots are saved only after the reports have been sent, so a crash or a reporter error no longer loses a change.
The default SQLite database is indexed and compressed and keeps the latest 4 snapshots of each job (set with –max-snapshots), so it no longer grows without limit.
Undo mistakes with –rollback-database and –delete-snapshot.
Tools for maintaining your jobs
–errors runs every job and lists those that fail or whose filters return nothing.
–test-differ replays the diffs of every snapshot saved, and –test without a job checks your jobs and configuration files for errors.
Editors such as VS Code autocomplete and validate
jobs.yamlandconfig.yamlfrom the JSON Schemas that webchanges installs next to them.The
!envtag reads secrets from environment variables instead of storing them in your files.Send different jobs to different destinations by configuring a reporter several times, each with its own tags, and open a GitHub issue with the GitHub Issue reporter.
Actively maintained
Releases ship regularly, supporting Python 3.12 to 3.15 (including the free-threaded build), and every release is tested on Linux, macOS and Windows.
Switching from urlwatch
Confirm that the latest release of urlwatch (2.29) runs your jobs without errors. webchanges reads the same files, so fix any error there first.
Install webchanges. If any of your jobs uses a browser (it has a
navigatedirective), install theuse_browserextra:uv pip install webchanges # or: uv pip install webchanges[use_browser]
Browser jobs use Google Chrome; if it is not installed, run
webchanges --install-chrome.Check your files:
webchanges --test # check the jobs and configuration files for errors
This first run copies your urlwatch files into webchanges’ own directory:
urls.yamlbecomesjobs.yaml,urlwatch.yamlbecomesconfig.yaml,hooks.pykeeps its name, and the snapshot databasecache.dbbecomessnapshots.db. webchanges looks for them where urlwatch keeps them (~/.urlwatch, or else its default directories), and copies only what it doesn’t have yet. The originals are left untouched, so urlwatch keeps working and you can switch back at any time.Fix what
--testreports, using What you may need to change. Renamed directives keep working and only print a deprecation warning, which you can address when convenient.Run webchanges. On the first run it converts its copy of urlwatch’s snapshot database to its own format, which needs the
minidbpackage for this one conversion:uv pip install minidb # needed once, for the conversion webchanges # run all jobs
You can uninstall
minidbafterwards. Don’t point--databaseat urlwatch’s legacycache.dbinstead of letting webchanges upgrade it into its own separate copy.All of the existing files are kept; if you don’t like what you see, you can keep on using urlwatch.
If you encounter a problem or have a suggestion, open an issue on GitHub.
What you may need to change
This section lists every difference, relative to urlwatch 2.29, that can require you to edit your files or change how you run the program.
Changes that stop a job or the run
Change these before your first run. (webchanges also rejects any directive it does not recognize, instead of ignoring it, so that a typo cannot go unnoticed.)
In urlwatch |
In webchanges |
|---|---|
|
|
|
Replace every |
Renamed names that still work
These names were changed for clarity, or replaced by a more capable equivalent. The old ones keep working (most print a deprecation warning), so you can update them when convenient:
urlwatch name |
webchanges name |
|---|---|
|
|
|
A |
|
|
|
wait_for_selector: |
|
|
|
|
|
|
|
|
|
|
|
stderr: |
|
|
|
|
|
The default method, ignoring |
|
|
|
|
|
|
|
|
|
Webhook (Slack, Mattermost etc.) (same sub-directives) |
|
Webhook (Slack, Mattermost etc.) with |
|
run_command, which inserts the report into the command line with |
|
|
Behavior that differs
None of these need an edit, but they change what you see:
The database format has been upgraded for speed, size, and to hold more detail. To keep using urlwatch’s database format, run with –database-engine minidb (requires the
minidbpackage).The html2text filter without a
methodconverts HTML to Markdown, while urlwatch’s default (re) only removed the tags; and itshtml2textmethod uses the Pythonhtml2textpackage, not thehtml2textprogram. Jobs using either report a change on their first run. To get the closest to urlwatch’s default output, addmethod: strip_tags.The database keeps the latest 4 snapshots of each job. To keep them all, as urlwatch does, set max_snapshots to 0 in
config.yamlor run with--max-snapshots 0.Jobs in reports are sorted alphabetically by name.
The
telegramreporter’smonospacesub-directive has no effect, as reports are sent in Markdown; it is reported as unrecognized.When run from a terminal,
--enable,--disableand--deleteask for confirmation before rewriting the jobs file, which (as in urlwatch) loses all its remarks (see Enable or disable a job).A job selected on the command line by its URL, command or name must match one job only; if it matches several, the error lists them and you select one by its index number instead (see Select subset of jobs).
On Windows with Python 3.12 to 3.14, a
UnicodeEncodeErrorfrom acommandjob or theshellpipefilter is fixed by running Python in UTF-8 mode (the default from Python 3.15).
Legal
The roots of webchanges from code of urlwatch 2.21 dated 30 July 2020 are credited throughout, and its code is appropriately copyrighted/licensed:
webchanges’ main page reads:
License
=======
Released under the `MIT License <https://opensource.org/licenses/MIT>`__ but redistributing modified source code from
`urlwatch 2.21 <https://github.com/thp/urlwatch/tree/346b25914b0418342ffe2fb0529bed702fddc01f>`__ dated 30 July 2020
licensed under a `BSD 3-Clause License
<https://raw.githubusercontent.com/thp/urlwatch/346b25914b0418342ffe2fb0529bed702fddc01f/COPYING>`__. See the
complete license `here <https://github.com/mborsetti/webchanges/blob/main/LICENSE.md>`__.
Each file with code contains this remark at the top:
# The code below is subject to the license contained in the LICENSE.md file, which is part of the source code.
Note: There is no requirement anywhere in law to spam the entire 61-line, 465 words license text on Every. Single. File. In. Every. Single. Directory; the above notice is amply sufficient.
The license file reads:
This software redistributes source code of release 2.21 of urlwatch
https://github.com/thp/urlwatch/tree/346b25914b0418342ffe2fb0529bed702fddc01f of 30 July 2021 which is subject to
the following copyright notice and license from
https://raw.githubusercontent.com/thp/urlwatch/346b25914b0418342ffe2fb0529bed702fddc01f/COPYING hereby retained
and redistributed with the source code (of which this license file is part of), in binary form, and in the
documentation. The appearance of the name of the author below does not constitute an endorsement or promotion of
this software by such author.
Copyright (c) 2008-2020 Thomas Perl <m@thp.io>
All rights reserved.
[follows full text of the urlwatch license]
(4) While a significant amount of improvements have been made from urlwatch 2.21, there’s no lack of proper and complete acknowledgement of the package’s use of Thomas Perl’s code – in multiple ways, exceeding the required full and explicit licensing language.