Updated 9 May 2026 · ~3 min read · built from each project's reference docs

webchanges vs urlwatch: a comparison

Both tools watch URLs, browser-rendered pages, and shell-command output for changes and notify you. webchanges does everything urlwatch does — same jobs, filters, and reporter model — and four high-value things urlwatch can't.

Bottom line: Pick webchanges if you need any of: TLS/JA3 fingerprint evasion for anti-bot sites, AI-summarized diffs of long documents, image change detection, or structural JSON/XML diffs without false positives. Or one of the many other additions, and a tool that is actively developed.

Release activity in the last 12 months

Source: GitHub releases on mborsetti/webchanges and tags on thp/urlwatch, as of 9 May 2026.

The 4 high-value wins

If any of these match what you actually monitor, urlwatch can't keep up. Each is a webchanges feature with no native urlwatch equivalent.

1Get past TLS/JA3 fingerprinting curl_cffi

Why it matters: Cloudflare, Akamai, DataDome and friends fingerprint the TLS handshake and HTTP/2 settings — not just User-Agent. urlwatch's stock requests client gets you a 403 with no recourse. webchanges routes through curl_cffi with a real browser TLS profile.

How: Set http_client: curl_cffi and impersonate: chrome (or safari / firefox / edge). Override fingerprints.ja3, fingerprints.akamai, or pin http_version as far as v3only.

url: https://hard-to-scrape.example/
http_client: curl_cffi
impersonate: chrome
http_version: v2tls

2Long diffs → one paragraph ai_google

Why it matters: Watching a 50-page terms-of-service, an RFC draft, a regulatory filing, or a long policy page? webchanges sends you a plain-English summary of the meaningful changes instead of a 2,000-line unified diff. urlwatch ships the raw patch and leaves you to read it.

How: differ: ai_google calls Google Gemini with a prompt template that exposes {old_text}, {new_text}, {unified_diff}. Configurable model, system_instructions, temperature, top_p, thinking_budget. Bring your own free Gemini API key.

differ:
  name: ai_google
  prompt: 'Summarize material changes by section.\n\n{unified_diff}'

3Watch images, not just text image

Why it matters: Logo swaps, product-photo updates, dashboard screenshots, status-page banners, captcha pages. urlwatch is text-first; if the page is a chart or an image, you're out. webchanges pixel-diffs and ships a yellow overlay showing what moved.

How: differ: image with data_type: url (or filename / ascii85 / base64) and mse_threshold (default 2.5) to tolerate compression noise.

url: https://example.com/logo.png
differ:
  name: image
  data_type: url
  mse_threshold: 5.0

4JSON/XML diffs that don't cry wolf deepdiff

Why it matters: APIs reorder keys. Numeric precision drifts. Whitespace flips. urlwatch text-diffs the serialized form and pings you for noise; you end up chaining format-json + jq + a custom diff_tool and still missing nested changes. webchanges compares the parsed structure element by element.

How: differ: deepdiff with data_type: json (or yaml / xml), ignore_order, ignore_string_case, significant_digits, compact.

differ:
  name: deepdiff
  data_type: json
  ignore_order: true
  significant_digits: 2

Use webchanges if…

Migration is mostly drop-in: jobs.yaml / config.yaml are largely compatible, and the database auto-migrates. Original files are retained so you can go back if you want.


Full reference comparison

Source: each project's official reference docs.

Jobs & universal directives

Directive webchanges urlwatch Notes
name, enabled, kind, user_visible_url, compared_versions, max_tries Common ground.
filter / filters, diff_filter / diff_filters Plural form in webchanges.
differ — typed differ selector with sub-directives × urlwatch only has diff_tool (a custom command).
note, monospace, is_markdown × Per-job rendering hints. webchanges-only
additions_only, deletions_only at job level filter-only webchanges promotes them to first-class job options.
tags, treat_new_as_changed × urlwatch-only
suppress_errors / suppress_repeated_errors / suppress_error_ended ~ Finer-grained muting in webchanges.
same_site_delay × Staggers jobs hitting the same site to dodge rate limits. webchanges-only
Shell job stderr handling (ignore/fail/stdout…) × urlwatch-only

HTTP client & fingerprinting

Capability webchanges urlwatch
Selectable client (httpx (HTTP/2), requests, curl_cffi) ×
http_version: v1, v2, v2tls, v2_prior_knowledge, v3, v3only ×
impersonate (chrome / safari / firefox / edge) ×
fingerprints.ja3, fingerprints.akamai, extra_fp ×
params, data_as_json, retries, no_redirects, no_conditional_request, empty_as_transient ~
Common: headers, cookies, data, method, encoding, timeout, ssl_no_verify, http_proxy/https_proxy, ignore_*_errors

Browser jobs (Playwright)

Both projects use Playwright and support the same engines (chromium, chrome, firefox, webkit, msedge). The difference is the directive surface, which is much broader for webchanges.

webchanges — use_browser: true

  • block_elements (skip stylesheets/images/fonts/media/scripts)
  • connect_over_cdp (attach to an already-running browser over the DevTools Protocol)
  • evaluate (run JS, return result)
  • init_script, initialization_url, initialization_js (initialize page before going to the URL with the data)
  • switches, ignore_default_args, user_data_dir(control browser launch)
  • http_credentials (log in, including a proxy)
  • ignore_https_errors, referer
  • wait_for_function, wait_for_selector (state / strict / timeout, list-able), wait_for_url, wait_for_timeout, wait_until

urlwatch — navigate:

  • navigate, wait_until, wait_for, useragent, browser

Same engine, much smaller knob set.

Filters

Both share the core (CSS/XPath, html2text, jq, pdf2text, OCR, regex, sort/reverse). Differences is the additional filters offered by webchanges.

Differs

Differ What it produces webchanges urlwatch
unified Standard line diff (context_lines, range_info) implicit
table HTML side-by-side table (tabsize) ×
wdiff Word-level diff with line breaks preserved ×
command Pipe to external program (is_html) diff_tool
deepdiff Structural JSON/YAML/XML diff ×
image Pixel diff with overlay ×
ai_google LLM summary via Gemini ×

Reporters

Reporter webchanges urlwatch Notes
Common: stdout, email (sendmail/SMTP), mailgun, telegram, matrix, gotify, ntfy, pushover, pushbullet, prowl, ifttt, xmpp, discord Both broad.
github_issue × Token, owner, repo, labels, assignees, milestone. webchanges-only
browser × Open HTML report locally. webchanges-only
run_command ~ webchanges substitutes {count}/{jobs}/{text} + WEBCHANGES_*_JSON; urlwatch has a simpler shell reporter.
webhook (unified Slack / Mattermost / custom) slack + mattermost webchanges merges them with markdown, max_message_length, rich_text.

Command-line interface

Webchanges adds operational tooling for testing, retention, recovery, observability, and packaging.

Flag What it does webchanges urlwatch
--errors [REPORTER] Test-run every enabled job and list ones that errored or captured no data; optionally pipe the result to a reporter. ×
--list-jobs [REGEX] List jobs and their indexes, filtered by an optional regex. urlwatch's --list has no filter. no regex
--test [JOB] Run one job and show filtered output. With no JOB, validates the syntax of every config, jobs, and hooks file. JOB required
--test-differ JOB Replay the differ against existing saved snapshots; combines with --test-reporter to preview the rendered output. --test-diff-filter
--no-headless Show the actual browser window for Playwright jobs (debug captchas, redirects, login walls). ×
--max-workers N Cap the parallel thread pool used to fetch jobs. ×
--clean-database [N] Trim snapshot history to the latest N per job (default 1). ×
--rollback-database TIMESTAMP Recovery undo: drop every changed snapshot newer than TIMESTAMP — the antidote to a bad filter that triggered a wave of false changes. ×
--delete-snapshot JOB Delete only the most recent snapshot for a job, e.g. to force a re-fetch. ×
--gc-database [N] Drop snapshots for jobs no longer in the jobs file. --gc-cache
--database-engine, --max-snapshots N Override the database engine and retention from the CLI without editing config.yaml. ×
--footnote "TEXT" Append a custom footer to every rendered report. ×
--log-file FILE Redirect logs to a file (defaults to verbose when set). ×
--check-new Query PyPI to see if a newer release of webchanges is available. ×
--detailed-versions Dump version info for webchanges, Python, SQLite, every dependency, the Playwright browser, and (on Linux) related apt packages — useful for bug reports. ×
--install-chrome Install or update the Chrome browser used by Playwright jobs. ×
--tags Select jobs to run by tag instead of by index. ×

Configuration & database

FAQ

What's the single biggest reason to choose webchanges?

The differ system ai_google turns a 2,000-line legal diff into three bullets; deepdiff kills false positives on JSON/XML; image watches pictures. urlwatch has none of these natively.

Can webchanges scrape sites that block urlwatch?

Often, yes. Use http_client: curl_cffi with impersonate: chrome (or safari/firefox/edge) and override fingerprints.ja3 / fingerprints.akamai if needed. urlwatch ships with no fingerprinting controls.

Is migrating from urlwatch hard?

Usually not. Job and config files are mostly compatible; the database auto-migrates. Original files are retained so you can go back if you want.

Does webchanges send my pages to Google?

Only if you opt in via the ai_google differ, which needs your own Gemini API key. Otherwise change detection is local.


Sources (reference docs)