Website Change Monitor: Page Diff & Alerts avatar

Website Change Monitor: Page Diff & Alerts

Pricing

from $20.00 / 1,000 page checkeds

Go to Apify Store
Website Change Monitor: Page Diff & Alerts

Website Change Monitor: Page Diff & Alerts

Watch web pages for changes and get only what changed: added and removed lines, links or HTML, for the whole page or one CSS selector, with ignore rules for dates and counters. Run it on a schedule and send alerts by email, Slack or Teams.

Pricing

from $20.00 / 1,000 page checkeds

Rating

0.0

(0)

Developer

Charles Markette

Charles Markette

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Website Change Monitor watches a list of web pages and tells you what changed since the last run. Each run fetches every page, takes the part you care about (the visible text, the HTML markup, or the set of links, optionally only inside a CSS selector such as .price or #stock), compares it with the snapshot saved by the previous run, and outputs the added and removed lines. Ignore the parts that change on every visit (dates, view counters, "updated 3 minutes ago") with regular expressions. Put it on a schedule and connect an alert, and you get an email or a Slack, Teams, Discord or Telegram message only when something changed.

Why this Actor

  • Shows what changed, not just that something did. Every changed page comes with addedLines, removedLines and a one-sentence changeSummary such as "3 lines added, 1 removed."
  • Watch exactly the part you need. A CSS selector per page (.price, #availability, main article), the same page watched twice with different selectors, labels you choose for each.
  • Quiet by design. Ignore patterns, Ignore numbers, Ignore upper/lower case and a Minimum change size keep counters and timestamps from raising alarms. In the default Changes only output, a run where nothing changed leaves the dataset empty, so alert integrations stay silent.
  • You notice when a watch breaks. Pages that fail to load and selectors that no longer match are always reported (status: "error" or "selectorNotFound"), and a failed check never overwrites the saved snapshot.
  • Light and polite. Plain HTTP requests (no browser), at most 2 requests at a time to any one host, retries with backoff on HTTP 429 and 5xx (honouring Retry-After), and a clear User-Agent (WebsiteChangeMonitor/1.0; +https://apify.com/charlesmarkette). Only public addresses are fetched; private, loopback and cloud-metadata addresses are refused, also after a redirect.

Use cases

  • Competitor pricing: watch .price on competitors' product and pricing pages.
  • Back-in-stock alerts: watch the availability label of a product.
  • Terms, policies and documentation: see the exact sentences that were added or removed from a terms-of-service, privacy policy or changelog page.
  • New articles, jobs or files: watch the links of a blog index, careers page or downloads page; added links are the new items.
  • Regulatory and public notices: watch announcement pages of agencies, schools or councils.
  • Your own site: get told when a deployment changes a page you didn't expect to change.

How to use it

  1. Add the Pages to watch. Plain URLs work, or objects that pick a part of the page and name it: {"url": "https://shop.example.com/mug", "cssSelector": ".price", "label": "Mug price"}.
  2. Give it a Monitor name (for example competitor-prices). Runs with the same name share one memory of snapshots, so you can add or remove pages later without losing history.
  3. Choose What to watch (visible text, HTML or links) and add Ignore patterns for anything that changes on every visit.
  4. Run it once: every page gets a baseline row (the first snapshot). From the second run on, you get a row for each page that changed.
  5. Schedule it and connect an alert (below).

Input example

{
"monitorName": "competitor-prices",
"startUrls": [
{"url": "https://shop.example.com/products/blue-mug", "cssSelector": ".price", "label": "Blue mug price"},
{"url": "https://shop.example.com/products/blue-mug", "cssSelector": "#availability", "label": "Blue mug stock"},
"https://www.example.org/terms"
],
"watch": "text",
"ignorePatterns": ["Last updated:? .*", "\\d+ people are viewing this"],
"outputMode": "changesOnly"
}

Output example (one changed page)

{
"url": "https://www.example.org/terms",
"label": null,
"finalUrl": "https://www.example.org/terms",
"statusCode": 200,
"checkedAt": "2026-10-22T08:00:05Z",
"status": "changed",
"changed": true,
"previousCheckedAt": "2026-10-21T08:00:04Z",
"lastChangedAt": "2026-10-22T08:00:05Z",
"addedLines": ["Refunds are available within 14 days of purchase.", "Disputes are handled in Delaware."],
"removedLines": ["Refunds are available within 30 days of purchase."],
"addedCount": 2,
"removedCount": 1,
"changeSummary": "2 lines added, 1 removed.",
"contentLength": 18452,
"contentHash": "4f3c9a…",
"title": "Terms of Service",
"watch": "text",
"cssSelector": null,
"monitorName": "competitor-prices",
"error": null,
"note": null
}

status is one of:

StatusMeaningIn Changes only output
baselineFirst time this page (with this selector and watch mode) is checked; its snapshot is saved.Yes
changedThe watched content differs from the last snapshot.Yes
unchangedSame as last time (after the ignore rules).No
errorThe page couldn't be checked: network error, HTTP 4xx/5xx, not a text page, or an invalid URL. The saved snapshot is kept.Yes
selectorNotFoundThe page loaded but nothing matches the CSS selector. The saved snapshot is kept.Yes

Errors and missing selectors are always reported, so you find out when a watch stopped working instead of hearing nothing. In Links mode, addedLines and removedLines hold absolute URLs. The lists hold at most Max diff lines per page entries; addedCount and removedCount are the full numbers. note explains special cases (a change below the minimum size, a page over 5 MB, content too big to list the lines). A run summary (counts, the changed URLs, the snapshot store's name) is saved as OUTPUT in the run's key-value store.

Run it on a schedule

  1. Save your input as a task (Actor page → Save as a new task), so every scheduled run uses the same pages and monitor name.
  2. In Apify Console open Schedules → Create new, set how often (for example every day at 08:00, or every hour), and add the task.

Each scheduled run compares with the previous one. Checking more often than a page actually changes only adds cost: daily is plenty for terms and policies, hourly suits prices and stock.

Get alerts by email, Slack, Teams, Discord or Telegram

Connect our Send Email Report & Slack, Discord, Teams, Telegram Alerts Actor as an integration:

  1. Open your monitoring task → Integrations → Add integration, pick that Actor and choose to run it when the run succeeded.
  2. In its input set the dataset to {{resource.defaultDatasetId}} (Apify fills in this run's output), add your email or webhook, and pick the fields to show, for example label, url, changeSummary, addedLines, removedLines, error.

By default that Actor sends nothing when the dataset is empty, and with Changes only the dataset is empty when nothing changed, so you hear from it only on changes, first checks and broken watches.

Ignoring noise

  • Ignore patterns are regular expressions (Python syntax) removed from each line before comparing: Updated \d+ (minutes|hours) ago, ©\s*\d{4}, \(\d+ views\). An invalid expression fails the run with a message saying which one.
  • Ignore numbers treats all numbers as equal (leave it off when you watch prices).
  • Ignore upper/lower case treats "In stock" and "IN STOCK" alike.
  • Minimum change size skips changes smaller than N characters (the size of the changed text, after the ignore rules). Small changes add up: until a change is reported, comparisons stay against the last reported version.

The lines in the output are shown as they appear on the page; the ignore rules only decide whether something counts as a change. If you edit the ignore settings later, the saved lines are compared again under the new rules, so editing them doesn't cause false alarms.

How much does it cost?

Pay per event: $0.02 per page checked. Apify platform usage is included, plus Apify's run start fee of $0.005 per run (one start event per GB of run memory; the default 256 MB run is charged one). Failed fetches are free: pages that couldn't be loaded (network errors, HTTP 4xx/5xx, non-text files) and invalid URLs cost nothing.

A page counts as checked when it loaded and was compared, whatever the outcome: baseline, changed, unchanged or selectorNotFound. That includes unchanged pages that Changes only leaves out of the dataset. A page listed twice with two selectors is two checks.

Worked examples:

  • 10 competitor pages checked once a day: 10 × $0.02 = $0.20 per run, about $6 per month.
  • 3 product pages checked every hour: 3 × 24 × $0.02 = $1.44 per day, about $43 per month.
  • 50 policy pages checked once a week: $1.00 per run, about $4.30 per month.

Each run in these examples also has the $0.005 run start fee (about $0.15 a month for a daily schedule).

If you set a maximum cost per run, the Actor stops cleanly at that limit; pages it didn't get to keep their snapshots and are compared on the next run.

FAQ and limits

Does it see content that JavaScript adds to the page?

No. It downloads the page over plain HTTP, like curl, and doesn't run JavaScript. Content that a script loads after the page opens (many single-page apps, some prices and stock widgets) isn't seen. If a selector shows selectorNotFound although you can see the element in your browser, that's the likely reason. Check by viewing the page source (Ctrl+U): if the text is there, this Actor sees it.

A site returns errors (403, 429, 503).

Some sites block automated requests or rate-limit them. The Actor retries a few times, then reports an error row (free) and keeps the old snapshot. It doesn't use proxies, log in, or solve CAPTCHAs, so sites that block bots can't be watched with it.

Where are the snapshots stored?

In a named key-value store in your Apify account, called change-monitor-<monitor name>-<short code> (the exact name is in the run summary). Named stores are kept until you delete them. Delete the store to start the monitor from scratch. Without a monitor name, the store is derived from the exact URL list, so changing the list starts new baselines; set a name to avoid that.

What resets a page to a new baseline?

Changing its CSS selector or the What to watch mode (a different part of the page can't be compared with the old one). Changing ignore settings doesn't, except for pages whose content was too big to keep the lines (below).

Are there size limits?

Pages are read up to 5 MB (the rest is ignored, and the row's note says so). The watched content of each page is kept as lines up to about 200 KB; beyond that only its hash is kept, so changes are still detected but the changed lines can't be listed. Use a CSS selector to watch a smaller part. Very large pages take more memory to parse; if a run runs out of memory, raise it to 512 MB. Up to 10,000 pages per run.

What counts as visible text?

What a reader sees: one line per paragraph, heading, list item or table row, whitespace collapsed. Scripts, styles, <noscript>, <template>, SVG and elements marked hidden are left out. HTML mode compares the markup of the selection (the page body by default) with attributes sorted and whitespace normalized, so a changed class or link target counts too.

Can I watch URLs from another Actor's output?

Yes: pick a Dataset of URLs and set the URL field. Set a monitor name as well, so the memory doesn't depend on the list.

Other tools by the same author

ActorUse it to
Send Email Report & Slack, Discord, Teams, Telegram AlertsGet a message after each run that found changes.
Google Sheets SyncKeep a log of every change in a Google Sheet.
Broken Link CheckerCrawl a whole site and find broken links and 404 pages.
Merge & Deduplicate DatasetsCombine the change rows of several monitors, or keep only new items between runs.