Page Change Monitor: Text Diff & Change Alerts API
Pricing
from $1.00 / 1,000 page checkeds
Page Change Monitor: Text Diff & Change Alerts API
Watch any web page (or one CSS section of it) for text changes. Each run returns changed true/false, a clean line diff (added/removed lines), a short summary and stable JSON for agents, MCP, schedules and webhooks. Ignores timestamps, ads and counters. $0.001 per page check.
Pricing
from $1.00 / 1,000 page checkeds
Rating
0.0
(0)
Developer
Tallow Lane Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Security
Limited permissionsShare
Page Change Monitor: text diff and change alerts for any web page
Watch any public web page, or one section of it, and get a clean answer on every run: changed: true/false, the exact lines added and removed, and a one-line summary. Built for Apify schedules, webhooks and AI agents (MCP), and it ignores noise like timestamps, ads, cookie banners and view counters.
Monitoring cost: a page with no changes costs $0.001 per check, so watching 10 pages daily is about $0.32 a month, plus $0.004 per change detected.
By Tallow Lane Labs. Checks only the pages you list, at most once per interval, politely and without unblockers. Tallow Lane Labs is not affiliated with the websites you monitor.
Why this one
- A real diff, not just "something changed". Line-level
addedandremovedlists, exact counts, achangeRatio, and a summary like Changed: 1 line added, 1 line removed. Added: "Pro $24/month". Removed: "Pro $20/month". - No false alarms from noise. Built-in rules ignore clock times, ISO timestamps, "5 minutes ago", view/like/comment counters, ad slots and cookie banners. Add your own CSS selectors or regular expressions. Calendar dates are kept, so a new "Last updated" date counts.
- Watch just the part you care about: a CSS selector (
#pricing,main article) or a text region ("from Changelog to Footer"), set globally or per page. - Stable JSON for agents. The same fields on every record, whatever happened:
status(ok,tooSoon,blocked,robotsDisallowed,httpError,error, ...),changed,firstSeen,changeType,diff,textHash,previousTextHashand timestamps. - Stateful by design. Snapshots live in a named key-value store, keyed by a hash of URL + selector + region, so a schedule simply runs the same input again.
- Polite and honest. One request at a time per site, a minimum check interval per page (5-minute floor), robots.txt respected, a truthful User-Agent, no proxies, no captcha solving. If a site blocks the check (403, 429, captcha or challenge page), the record says
blockedand why, and the old snapshot is kept.
Use cases
- Competitor pricing and plan pages: get the exact price line that changed.
- Terms, privacy and policy pages: see what changed in a ToS or privacy policy.
- Docs, changelogs and status pages: get new releases or incidents as diffs.
- Government, procurement and regulatory notices.
- Agent memory: let an AI agent ask "did this page change since I last read it, and how?"
Quick start
- Click Try for free and run the example page, or leave
urlsempty for a 2-page demo. - Add your pages, one URL per line. Optionally set a CSS selector.
- Schedule the Actor (for example daily or hourly). The first run stores a baseline, and every later run reports changes.
- Add a webhook or Slack/Zapier/Make integration on Run succeeded.
RUN_SUMMARY.changedUrlslists what changed.
Input example
{"urls": ["https://www.iana.org/help/example-domains"],"pages": [{ "url": "https://acme.com/pricing", "selector": "#plans", "label": "Acme pricing" },{ "url": "https://acme.com/legal/terms", "regionStart": "Terms of Service", "regionEnd": "Contact us","minCheckIntervalMinutes": 1440 }],"ignorePatterns": ["^Sponsored.*$"],"outputMode": "all","minCheckIntervalMinutes": 60}
Main options:
urls: leave empty for a demo.pages: per-pageselector,regionStart/regionEnd,ignoreSelectors,ignorePatterns,labelandminCheckIntervalMinutes.- Global
selector, region and ignore rules. useDefaultIgnoreRules: on by default.minCheckIntervalMinutes: 60 by default, minimum 5.outputMode:all(default) orchangesOnly.includeText,maxDiffLinesandrespectRobotsTxt.domainDelayMs: 2,000 ms by default, minimum 1,000.stateStoreName,stateKeyPrefixandresetState.
See the Input tab for every field.
Output example
An example record for a changed page (hashes shortened):
{"recordType": "page","url": "https://acme.com/pricing","label": "Acme pricing","finalUrl": "https://acme.com/pricing","status": "ok","httpStatus": 200,"changed": true,"firstSeen": false,"changeType": "changed","summary": "Acme pricing: Changed: 1 line added, 1 line removed (25% of the text) since 2026-11-02T12:00:03.101Z. Added: \"Pro $24 per month\". Removed: \"Pro $20 per month\".","diff": {"added": ["Pro $24 per month"],"removed": ["Pro $20 per month"],"addedCount": 1, "removedCount": 1, "truncated": false, "changeRatio": 0.25, "algorithm": "myers"},"textHash": "9f2c…", "previousTextHash": "41d8…","lineCount": 4,"title": "Pricing - Acme","selector": "#plans","checkedAt": "2026-11-03T12:00:02.877Z","previousCheckedAt": "2026-11-02T12:00:03.101Z","lastChangedAt": "2026-11-03T12:00:04.950Z","nextCheckAllowedAt": "2026-11-03T13:00:04.950Z","blockedReason": null,"error": null}
status | Meaning | Charged |
|---|---|---|
ok | Checked. changeType is firstSeen, changed, unchanged or baselineReset (ignore rules changed) | page check (+ change if changed) |
tooSoon | Checked less than minCheckIntervalMinutes ago. Not fetched; nextCheckAllowedAt says when | no |
blocked | 403, 429, captcha or bot challenge. blockedReason is rateLimited, challenge, captcha, forbidden, authRequired or legal | no |
robotsDisallowed | The site's robots.txt disallows the page | no |
httpError / error / invalidUrl / unsupportedContent | 404 and similar errors, network failure, a bad URL, or a PDF or image | no |
selectorNotFound / regionNotFound | The selector or region start text is not on the page (the old snapshot is kept) | no |
- Error records,
blockedrecords andtooSoonrecords are never charged. RUN_SUMMARY(key-value store) hastotals,changedUrls,blockedUrls, a per-page list and HTTP stats.- Dataset views: Page checks, Diffs, and Skipped, blocked and failed.
Pricing (pay per event)
| Event | Price | When |
|---|---|---|
| Page checked | $0.001 | Each page fetched and compared (first check, changed or unchanged) |
| Change detected | $0.004 | Extra, only when the page's cleaned text changed (with diff and summary) |
| Actor start | $0.0005 | Once per run (same at 256, 512 or 1,024 MB) |
Not charged: tooSoon skips, blocked pages, robots.txt skips, failed fetches, selector or region misses, and error records.
- 20 pages, no changes: $0.0205 per run (about $0.62 a month daily).
- 10 pages hourly with no changes: about $7.56 a month. A changed page costs $0.005 in total for that check.
- Set Apify's maximum cost per run for a hard cap. The Actor stops before pages it can't pay for. A change it can't pay for is reported on the next run, never lost.
Integrations
- Schedules: Apify Console → Schedules → run this Actor with your input daily or hourly. Use a
minCheckIntervalMinutesequal to the schedule period. A 10% early-start tolerance means an hourly schedule is never skipped astooSoon. - Webhooks, Slack, email, Make, Zapier, n8n: add an integration on Run succeeded. Use
outputMode: changesOnlyso the dataset holds only changes and problems. - Apify API:
POST https://api.apify.com/v2/acts/tallowlanelabs~page-change-monitor/run-sync-get-dataset-items, or
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("tallowlanelabs/page-change-monitor").call(run_input={"urls": ["https://acme.com/pricing"], "selector": "#plans"})for page in client.dataset(run["defaultDatasetId"]).iterate_items():if page["changed"]:print(page["summary"])
- AI agents (MCP):
https://mcp.apify.com?tools=tallowlanelabs/page-change-monitorlets an assistant answer "did this page change, and what changed?"
FAQ
Why did my first run say firstSeen and not show a diff? There was nothing to compare with yet. The first check stores the baseline, and changes are reported from the next run.
Why tooSoon? Each page is fetched at most once per minCheckIntervalMinutes (at least 5 minutes), however often the Actor runs. This keeps monitoring polite. The record says when the next check is allowed.
A timestamp or counter keeps triggering changes. Add a regular expression to ignorePatterns (for example Last refreshed .*) or a CSS selector to ignoreSelectors. Changing ignore rules re-baselines the page (baselineReset) instead of reporting a false change.
Does it render JavaScript? No. It reads the HTML the server sends, plus plain text, JSON and XML. Pages that build their content only in the browser may show little text. Point it at the site's server-rendered page or JSON endpoint instead.
What if a site blocks it? You get status: "blocked" with the reason. The Actor never uses unblockers, rotating proxies or captcha solvers, and it doesn't retry blocks.
Is it legal? It reads public pages you choose, once per interval, honouring robots.txt, with a User-Agent that names the tool. Don't monitor logged-in pages or personal profiles, and follow each site's terms. (General information, not legal advice.)
Limits
- Public pages only: no logins and no JavaScript rendering.
- Up to 1,000 pages per run, and 5 MB of HTML per page.
- Stored text is capped at 1,000,000 characters per page.
- Up to 200 diff lines per side by default (counts are always exact).
- 256 MB of memory covers normal pages. Use 512 MB for many very large pages.
Support
Open an issue on the Issues tab or email Tallow Lane Labs at wdeornellas+tallowlanelabs@gmail.com.