Catalog / page-diff-watch
page-diff-watch
"Has the text of this public page (or one part of it) changed since I last looked?" The first call stores a baseline. Each later call fetches the page again and reports changed or not, which lines were added or removed, and a short rule-based summary including price-like tokens that moved.
What question it answers
"Has the text of this public page (or one part of it) changed since I last looked?" The first call stores a baseline. Each later call fetches the page again and reports changed or not, which lines were added or removed, and a short rule-based summary including price-like tokens that moved.
When to use it
- Watching a pricing page, a changelog, a status note or a policy page for any text change.
- Narrowing to one part with a CSS selector (for example
main h1). - Pages that need JavaScript to render: set
js_render(needs Chromium on the machine; otherwise it falls back to plain fetch and says so).
When not to
- Not for LinkedIn, Facebook, Instagram, TikTok, X or Twitter (blocked on purpose), or private/internal addresses.
- Not for pages whose robots.txt disallows the path: you get
blockedByRobots:trueand no data. - The diff is a set of changed lines; it ignores line order. A reordered page shows no change.
- The summary is regex-based. Price and number "shifts" are pairings by position, not proof.
Example (MCP tool `check_page_change`, or CLI)
npx tsx src/cli.ts https://example.com/ --selector h1
Second call on a changed page, trimmed (shape from samples/httpbin-uuid-change.json):
{
"tool": "page-diff-watch",
"version": "0.2.0",
"url": "https://httpbin.org/uuid",
"httpStatus": 200,
"fetchMode": "static",
"selector": null,
"selectorMatched": null,
"robots": { "allowed": true, "checked": true, "reason": "no matching disallow" },
"firstCheck": false,
"changed": true,
"previousHash": "9601cf1c...",
"hash": "db621474...",
"changeRatio": 0.33,
"addedLineCount": 1,
"removedLineCount": 1,
"summary": { "paragraph": "Page https://httpbin.org/uuid changed with 1 added and 1 removed line(s) ...", "pricesChanged": [], "numbersChanged": [] },
"unifiedDiffPreview": "- ...\n+ ...",
"billing": { "sku": "page_check", "plannedPriceUsd": 0.01, "x402Enabled": false }
}
First call: firstCheck:true, changed:null, summary "First baseline saved ...". If the page returns a server error or rate-limit status after a good baseline, you get changed:null, baselinePreserved:true and an error string instead of a fake change.
Data source and licence
The page you name. The tool does not read the site's terms of use; it only checks robots.txt. You are responsible for having the right to monitor that page. The tool keeps the page's extracted text on disk as the baseline.
Freshness, state and limits
- Every call fetches the live page (no result cache).
- Baselines live on the machine that runs the tool, per tenant name; if you share one tenant, you share baselines.
- Static fetch: 25 s timeout, 2 MB cap.
- Known gaps: a 404/410 response currently replaces the baseline; robots parsing is simplified and allows the fetch when robots.txt cannot be read or returns a server error.
- Browser mode has a known DNS-rebinding gap; use static mode for untrusted URLs.
Errors are not charged
Payment settles only on a successful answer. Any response with status 400 or higher (bad input, not found, upstream failure) is never settled.