Website Change Monitor - Page Change Detection & Alerts avatar

Website Change Monitor - Page Change Detection & Alerts

Pricing

Pay per event

Go to Apify Store
Website Change Monitor - Page Change Detection & Alerts

Website Change Monitor - Page Change Detection & Alerts

Website change tracker and content monitor: text and price changes, CSS selector per URL, keyword triggers, noise filters, screenshots, email, Slack, Discord, webhook alerts, AI summary. $2/1k checks.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Yukai Lin

Yukai Lin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 hours ago

Last modified

Share

What does Website Change Monitor do?

It watches web pages and tells you what changed since the last check: which text was added and which was removed. Run it on a schedule (hourly, daily, weekly) and get the changes in the dataset, by e-mail, in Slack or Discord, or pushed to a webhook (Zapier, Make, n8n, your own app). It accepts Content Checker inputs (url, contentSelector, sendNotificationTo and more), takes before and after screenshots, and can watch thousands of pages in one run.

  • ๐Ÿ” Remembers the previous version of every page between runs, so each run is a real comparison (or compare with a locked baseline you approved)
  • ๐ŸŽฏ Watch only what matters: a CSS selector for the whole run or per page (#pricing, .product-price, main), with an optional fallback to the whole page when the element disappears
  • ๐Ÿ”‡ Less noise: ignore dates, times, "5 minutes ago" and view counters with one switch, add your own ignore patterns, and set a minimum size for a change to count
  • ๐Ÿ”‘ Keyword triggers: alert only when a changed line mentions "price", "out of stock" or any words you choose
  • ๐Ÿ”ข Number changes: price and percentage changes are extracted ($19 โ†’ $29)
  • ๐Ÿค– Optional AI summary: one or two sentences on what changed, plus a significance score from 1 (trivial) to 5 (critical)
  • ๐Ÿ“ฌ Alerts: e-mail (via Apify's send-mail Actor), Slack and Discord messages, or JSON webhooks with an optional HMAC-SHA256 signature
  • ๐Ÿ“ธ Before and after screenshots (optional): a screenshot of the page, or of just the watched element, on every alerted change, linked in results and alerts. Cookie and consent banners are always removed before the screenshot (verified on IKEA, The Guardian and apify.com), so the images show the page, not the banner
  • ๐Ÿšจ Alerts when a page keeps failing: get told when a page could not be read (or its element vanished) several runs in a row, so a monitor never fails silently
  • ๐Ÿ—‘๏ธ Removed pages are reported: a watched page that starts answering 404 or 410 is reported as removed and alerted once (on by default, not charged), and as restored when it comes back
  • โš™๏ธ No false alerts after a settings change: changing the CSS selector, ignore rules or mode saves a new baseline (reason: "settings-changed") instead of reporting the whole page as changed
  • ๐ŸŒ Works on protected and JavaScript sites: pages are read over plain HTTP first, with automatic fallback to another network and a real browser
  • ๐Ÿ’ธ $2 per 1,000 page checks, no extra fee per detected change; failed checks are free

Content Checker alternative

If you use a Content Checker-style Actor today, your input works as it is: url, contentSelector, screenshotSelector, sendNotificationTo and informOnError are accepted.

Migrate in one minute

Paste your Content Checker input into this Actor's JSON input, keep your schedule, and that's it:

{
"url": "https://www.apify.com/change-log",
"contentSelector": "article",
"screenshotSelector": "article",
"sendNotificationTo": "you@your-apify-account-email.com",
"informOnError": "true"
}

screenshotSelector turns on change screenshots of that element ($0.003 each), and informOnError: "true" alerts you from the first failed check. To watch more pages in the same run, move them into urls (one entry per page, each with its own selector and name):

{
"urls": [
{ "url": "https://www.apify.com/change-log", "userData": { "selector": "article", "name": "Apify changelog" } },
{ "url": "https://example.com/pricing", "userData": { "selector": "#plans", "name": "Competitor pricing" } }
],
"monitorName": "my-watchlist",
"screenshotOnChange": true,
"alertOnError": true,
"notifyEmail": "you@your-apify-account-email.com"
}
Content Checker fieldThis ActorNotes
urlurl or urlsurls takes many pages in one run (up to 5,000)
contentSelectorcontentSelector or cssSelectorAlso per page: {"url": "...", "userData": {"selector": "#price", "name": "Pricing"}}
sendNotificationTosendNotificationTo or notifyEmailSent with apify/send-mail, which delivers to your Apify account's e-mail address
screenshotSelectorscreenshotSelector, or screenshotOnChange (uses the watched selector)Screenshot after the change plus the previous one ("before"), in results and alerts
informOnErrorinformOnError or alertOnError + errorThresholdAlert after N failed runs in a row (Content Checker's informOnError = after the first), plus a "works again" note
(none)webhookUrl, webhookSecretSlack, Discord or JSON, optionally signed
(none)watchKeywords, minChangedLines, minChangeRatio, ignoreCommonNoiseFewer false alarms
(none)aiSummaryWhat changed and how much it matters

What stays the same for you: a schedule in Apify Console runs the check, and each run compares with the last one. What you gain: many pages per run, per-page selectors, automatic browser fallback, noise filters, and failed checks are not charged.

Use cases

  • Competitor monitoring: pricing pages, product catalogs, feature lists, job openings (use watchKeywords like "price" and read numericChanges)
  • Compliance & legal: terms of service, privacy policies, regulatory pages (use a locked baseline to compare with the approved version)
  • Release tracking: changelogs, download pages, documentation
  • Content watch: news pages, government notices, stock or availability pages

How much does it cost?

EventPrice
Page check$2.00 / 1,000 checks
AI change summary (optional)$0.005 per changed page summarized
Change screenshot (optional)$0.003 per screenshot

No start fee and no fee per detected change: the base check price is fixed, and only optional features are charged per use.

MonitorChecks per monthCost per month
1 page, every hour720$1.44
1 page, every hour, with screenshots and 10 alerted changes720 + 11 screenshots$1.47
20 pages, once a day600$1.20
100 pages, once a day3,000$6.00

With screenshots on, one screenshot is taken when the baseline is saved (or the first time a page has none) and one per alerted change; unchanged checks take no screenshot. Pages that could not be read, and pages whose CSS selector matched nothing, are not charged. E-mail alerts run apify/send-mail on your account (a few seconds of platform usage). Higher Apify plans get volume discounts (see the Pricing tab).

Content Checker itself has no Actor fee in the Apify Store; you pay Apify platform usage for its browser runs, which depends on your plan (checked September 2026). For comparison, some change monitors in the Apify Store charge $0.008 to $0.02 per detected change on top of each check, and AI change summaries elsewhere cost $0.02 to $0.06 each (checked September 2026).

Control your cost

  • Charged: each page that was read and compared ($0.002), plus screenshots ($0.003) and AI summaries ($0.005) only if you turn them on.
  • Free: pages that could not be read, removed pages (404 / 410), pages whose CSS selector matched nothing, and invalid input lines. Every row has charged: true or false, and the error text of free rows ends with "(not charged)".
  • At the start, the log and status message show the plan: number of pages ร— price (and the most that screenshots or AI summaries could add) = the most the run can cost, compared with your maximum charge per run (set in the run options).
  • When that maximum is reached, the run stops checking new pages. The status message says how many were not checked, SUMMARY.notProcessed lists them (count and up to 100 URLs), and the webhook and e-mail are still sent with incomplete: true and uncheckedPages, so an integration does not read "no alert" as "no changes".

How to use it

  1. Paste the pages to watch, one URL per line (example.com/pricing works too). A line that is not a URL gets its own error row (errorType: "invalid_input", not charged) and the other pages are still checked. For per-page settings, use Pages with per-page settings and add user data to a URL: {"selector": "#pricing", "name": "Competitor pricing"}.
  2. Give the monitor a name (runs with the same name compare against each other).
  3. Optional: set a CSS selector, ignore patterns, keywords, and alerts (e-mail, webhook URL).
  4. Run it once to save the baseline, then create a schedule in Apify Console (Schedules โ†’ Create, pick this Actor and your input, choose e.g. "every day at 9:00") to run it automatically.
  5. Optional: turn on Screenshot changed pages and Alert when a page keeps failing (Alerts and noise control). Alert when a page is removed is on by default.
  6. Want to check your alert setup first? Turn on Test alerts without sending (Alerts and noise control): the webhook is not called and the e-mail uses send-mail's mock mode; the result is in the SUMMARY record.

Input example

{
"urls": [
{ "url": "https://www.python.org/downloads/", "userData": { "selector": ".download-list-widget", "name": "Python releases" } },
{ "url": "https://example.com/pricing", "userData": { "selector": "#plans", "name": "Competitor pricing" } }
],
"monitorName": "competitors",
"ignoreCommonNoise": true,
"watchKeywords": ["price", "release"],
"aiSummary": true,
"outputOnlyChanges": true,
"webhookUrl": "https://hooks.slack.com/services/...",
"notifyEmail": "you@your-apify-account-email.com"
}

Output

The first run saves a baseline ("status": "first-check"). Later runs report unchanged or changed. A real changed result (September 2026, httpbin.org/uuid returns a new ID on every request):

{
"url": "https://httpbin.org/uuid",
"status": "changed",
"checkedAt": "2026-09-29T02:38:51.571Z",
"addedCount": 1,
"removedCount": 1,
"changeRatio": 0.333,
"added": ["\"uuid\": \"03c057ca-3989-4dd3-9bbe-076de0a0eb27\""],
"removed": ["\"uuid\": \"3f613ece-f6a4-4943-bfa1-d6a33a3ce95a\""],
"significant": true,
"aiSummary": "The UUID value changed from 3f613ece-f6a4-4943-bfa1-d6a33a3ce95a to 03c057ca-3989-4dd3-9bbe-076de0a0eb27",
"significance": 1,
"mode": "browser",
"via": "browser"
}

Other fields you may see:

  • significant: false with a minorReason (for example "no watched keyword in the changed lines"): reported, but no alert
  • numericChanges: [{ "before": "$19", "after": "$29", "context": "Pro plan $29/month" }]
  • noiseOnly: true on an unchanged page: only dates, times or counters differed (with Ignore dates, times and counters)
  • reorderedOnly: true on an unchanged page: the same lines only moved around, so there is nothing to show and no alert
  • Very long lines (table layouts such as Hacker News or price tables often convert to one huge line) are compared in short pieces, so added / removed show the part that changed, not a 10,000-character line
  • status: "selector-not-found": the watched element is missing (real example: {"status": "selector-not-found", "name": "Missing element", "selector": "#nope-xyz", "message": "The CSS selector \"#nope-xyz\" matched nothing on the page. ..."}); with Fall back to the whole page, the whole page is compared instead and selectorFallback: true is set
  • Locked baseline: baselineAt, driftedSince and newSinceLastRun (alerts fire only when the page differs from what the previous run saw)
  • status: "failed" with error, errorType and consecutiveFailures (not charged; the baseline is kept)
  • On first-check: watchedPreview (the first lines of the watched text) and watchedLines, so you can see whether your CSS selector picked the right part of the page. After a settings change: reason: "settings-changed"
  • status: "removed" with httpStatus (404 or 410), removedAt and significant: true the first time (not charged; the baseline is kept). When the page is back, the result carries restored: true
  • Every row has charged: true or false; successful rows also carry finalUrl and httpStatus. A line that is not a URL: { "input": "acme", "status": "invalid-input", "errorType": "invalid_input", "charged": false }
  • With Screenshot changed pages: screenshotUrl (JPEG after the change, or the baseline shot on the first check) and previousScreenshotUrl (the "before" image: the last screenshot saved for that page; with a locked baseline, the baseline's screenshot). screenshotError if the screenshot failed (not charged)

A real screenshot result (September 2026, httpbin.org/uuid with screenshots on, second run):

{
"url": "https://httpbin.org/uuid",
"status": "changed",
"addedCount": 1,
"removedCount": 1,
"added": ["\"uuid\": \"762816a2-8e92-4d9a-aa9a-05b68c05601e\""],
"removed": ["\"uuid\": \"e83ca153-a8dc-498e-b49c-80ddb4cfe18e\""],
"significant": true,
"screenshotUrl": "https://api.apify.com/v2/key-value-stores/NGtk6Pi14T1p0800F/records/shot-f5056fea96bf70021469b9ac93aae968-20260929034729491.jpg?signature=โ€ฆ",
"previousScreenshotUrl": "https://api.apify.com/v2/key-value-stores/NGtk6Pi14T1p0800F/records/shot-f5056fea96bf70021469b9ac93aae968-20260929034644443.jpg?signature=โ€ฆ"
}

With Alert when a page keeps failing (alertOnError, errorThreshold), pages that failed that many runs in a row are listed in the alert under Problems, once per failure streak, and pages that work again are listed under Recovered. Real SUMMARY excerpt (httpbin.org/status/503, threshold 2, second run):

{
"problems": [{ "event": "problem", "url": "https://httpbin.org/status/503", "count": 2, "status": "failed", "error": "target returned HTTP 503" }],
"notifications": [{ "channel": "webhook", "ok": true, "kind": "json", "status": 200 }]
}

The JSON webhook receives { "monitor": "...", "checkedAt": "...", "changes": [ { "url", "name", "title", "addedCount", "removedCount", "added", "removed", "matchedKeywords", "numericChanges", "aiSummary", "significance", "screenshotUrl", "previousScreenshotUrl" } ], "problems": [ ... ] } (problems only with error alerts), plus incomplete and, when the run stopped at your maximum charge limit, uncheckedPages. A removed page appears in changes with pageRemoved: true and httpStatus; a page that is back has restored: true. With a signing secret, verify the X-Signature-256: sha256=<hex> header (HMAC-SHA256 of the raw body). The SUMMARY record has status (SUCCESS, PARTIAL_RESULTS, FAILED, NO_RESULTS or LIMIT_REACHED), counts and the result of each alert.

Use with AI agents (MCP)

Connect Apify's MCP server (https://mcp.apify.com?tools=tidytools/website-change-monitor) to Claude, Cursor or any MCP client, then ask e.g. "Check whether the pricing pages of these three competitors changed since last week and summarize what changed."

{ "urlList": ["https://example.com/pricing"], "monitorName": "pricing", "aiSummary": true }

Failed items are not charged and carry an errorType.

Use it from code and integrations

Run it from your own code with the Apify API. This call waits for the run and returns the results as JSON (replace YOUR_TOKEN with your Apify API token):

curl -X POST "https://api.apify.com/v2/acts/tidytools~website-change-monitor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urlList":["https://www.python.org/downloads/","https://news.ycombinator.com"]}'

The synchronous endpoint waits up to 5 minutes. For bigger runs, start the run with POST https://api.apify.com/v2/acts/tidytools~website-change-monitor/runs and read the dataset when it finishes, or use the apify-client package for JavaScript or Python.

Schedules and integrations: run it daily or weekly with Apify Schedules, get a webhook when a run finishes, or send the results to Zapier, Make, n8n, Google Sheets, Slack and other apps with Apify integrations. Results can be exported as JSON, CSV, Excel or XML.

Tips

  • Use Only output changed pages for scheduled runs, so the dataset contains just the news.
  • Rotating banners, ads or "related articles" blocks: list their CSS selectors in Ignore these parts of the page; they are removed before comparing.
  • If a page reports changes every time, turn on Ignore dates, times and counters, add ignore patterns for the parts that always differ (rotating banners), set Minimum changed lines, or narrow the CSS selector.
  • Use different monitor names for independent watch lists.
  • Advanced settings: Plain HTTP requests from and Proxy help with sites that block data-center requests (proxy usage is billed to your Apify account).

Limitations

  • Compares page text, not images or layout. Screenshots are taken in a separate browser visit right after the check, so a page that changes on every request (like a random ID) can differ slightly from the compared text.
  • Login and newsletter pop-ups are hidden too, and full-page screenshots pin sticky headers so they appear once, as soon as the capture backend supports it (the item then lists what was removed in screenshotCleanup).
  • Screenshot links are signed links to your monitor's key-value store; the 5 newest screenshots per page are kept (plus the locked baseline's).
  • Lines that only moved position are not reported as changes.
  • E-mail alerts use apify/send-mail, which only delivers to the e-mail address of your Apify account. For other recipients, use a webhook (Zapier, Make) or Slack.
  • Only public pages; no logins.

FAQ

How often can it check a page? As often as your Apify schedule runs it: hourly, daily or weekly. One page checked every hour is 720 checks, about $1.44 per month.

Can it monitor price changes? Yes. Watch only the price element with a CSS selector (e.g. .product-price), and price and percentage changes are extracted ($19 โ†’ $29). Keyword triggers can limit alerts to lines that mention words you choose.

How do I get alerts? By e-mail to your Apify account address, in Slack or Discord, or with a JSON webhook to Zapier, Make, n8n or your own app.

Will it alert me about dates and counters that change on every visit? Not if you turn on Ignore dates, times and counters: dates, times, "5 minutes ago" and view counters are ignored, and you can add your own ignore patterns and a minimum change size.

Support

Open an issue in the Issues tab with the URL and your input. Issues are checked regularly.