Website Change Monitor - Page Change Detection & Alerts
Pricing
from $1.60 / 1,000 page checks
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
from $1.60 / 1,000 page checks
Rating
0.0
(0)
Developer
Yukai Lin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
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) and the input fields of other change monitors (startUrls, kvStoreName, slackWebhookUrl...), takes before and after screenshots, and can watch thousands of pages in one run.
Quick start
- Paste the URLs you want to watch (one per line) and give the monitor a name.
- Run it once: this saves the baseline (
"status": "first-check"), so the first run reports no changes yet. - Add a daily schedule in Apify Console → Schedules (Create → pick this Actor and your input). Every scheduled run then reports what changed and sends your alerts.
- 🔁 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
removedand alerted once (on by default, not charged), and asrestoredwhen 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 field | This Actor | Notes |
|---|---|---|
url | url or urls | urls takes many pages in one run (up to 5,000) |
contentSelector | contentSelector or cssSelector | Also per page: {"url": "...", "userData": {"selector": "#price", "name": "Pricing"}} |
sendNotificationTo | sendNotificationTo or notifyEmail | Sent with apify/send-mail, which delivers to your Apify account's e-mail address |
screenshotSelector | screenshotSelector, or screenshotOnChange (uses the watched selector) | Screenshot after the change plus the previous one ("before"), in results and alerts |
informOnError | informOnError or alertOnError + errorThreshold | Alert after N failed runs in a row (Content Checker's informOnError = after the first), plus a "works again" note |
| (none) | webhookUrl, webhookSecret | Slack, Discord or JSON, optionally signed |
| (none) | watchKeywords, minChangedLines, minChangeRatio, ignoreCommonNoise | Fewer false alarms |
| (none) | aiSummary | What 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.
Switching from another website change monitor
Using another change monitor from the Apify Store? Paste your existing JSON input as it is. The common field names of other monitors are accepted, and the run log lists each field that was mapped (and the few that are not used):
| Their field | Read as | Notes |
|---|---|---|
urls (list of URLs), startUrls ([{ "url": ... }]), wccInput.startUrls | pages to watch | Exactly these pages are checked; linked pages are not crawled |
urls with { "url", "label", "selectors": { "content", "ignore" } } | per-page name and CSS selector | Per-page ignore selectors apply to all pages |
kvStoreName | monitorName | |
notifyOnlyChanges | outputOnlyChanges | |
slackWebhookUrl, alerts.webhookUrl | webhookUrl | Slack gets a formatted message; with both set, both are called |
ignoreNoise | ignoreCommonNoise | |
mode: text, html or selector | auto | The visible text is compared; cssSelector watches one part of the page |
baselineMode: latest / locked | rolling / locked | |
diff.ignorePatterns, diff.minChangePercent | ignorePatterns, minChangeRatio | 1.5 (%) becomes 0.015 |
maxRequestsPerCrawl | most pages checked per run | |
outputEmail | notifyEmail | apify/send-mail delivers to your Apify account's e-mail address |
cssSelector, webhookUrl, watchKeywords, ignorePatterns, ignoreSelectors, resetBaseline | same name |
Not used: severity levels (minSeverity; use minChangedLines, minChangeRatio or watchKeywords), extra layers such as metadata or links (layers; the visible text is compared), sitemap discovery (list the pages), Notion and Slack connectors (use a Slack webhook URL). Paid extras are never switched on by a pasted field: set aiSummary or screenshotOnChange yourself if you want them. Your old monitor's history is not imported, so the first run saves a new baseline.
Paste your existing input
An input written for another monitor, unchanged:
{"urls": ["https://example.com/pricing", "https://example.com/changelog"],"mode": "text","cssSelector": "main","notifyOnlyChanges": true,"kvStoreName": "competitors","slackWebhookUrl": "https://hooks.slack.com/services/...","watchKeywords": ["price", "plan"],"ignoreNoise": true,"baselineMode": "latest"}
Here it watches the main part of both pages under the monitor name competitors, outputs only changed pages, posts changes that mention "price" or "plan" to Slack, ignores dates and counters, and compares each run with the previous one.
How the prices compare
Store prices on the Free plan, checked October 2, 2026 (see each Actor's Pricing tab for current prices):
| This Actor | Website Change Monitor & Diff Tracker | Competitor Marketing Change Monitor | |
|---|---|---|---|
| Price per 1,000 page checks | $2.00 ($1.60 to $1.80 on higher plans) | $100 per 1,000 sites ($18 to $47 on higher plans) | $3.00 ($0.002 per page + $0.001 per result) |
| Start fee per run | none | $0.00005 | $0.25 per GB of memory |
| Failed pages | free | not stated | not stated |
| 20 pages once a day (600 checks a month) | $1.20 | $60 | at least $9.30 |
| Screenshots | optional, $0.003 each, before and after | no screenshot option | yes, on by default |
| Strong points | many pages per run, per-page selectors, browser fallback, removed-page alerts, signed webhooks | change severity levels, SEO metadata, link and tech-stack layers, Notion and Slack connectors, sitemap discovery | marketing-page focus, screenshots |
Use cases
- Competitor monitoring: pricing pages, product catalogs, feature lists, job openings (use
watchKeywordslike "price" and readnumericChanges) - 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
Product price and stock monitor (no selector)
Set watchProduct: true to compare structured product metadata instead of the page's visible text. It reads JSON-LD Product → Offer/AggregateOffer (using lowPrice for an aggregate), then product:price:amount, product:price:currency and product:availability meta tags. The dataset includes price, currency, availability (InStock or OutOfStock), and previousPrice. A first check saves the baseline; later price drops and stock flips can trigger your existing webhook or e-mail alert. For example:
{ "urlList": ["https://example.com/product"], "monitorName": "product-watch", "watchProduct": true, "priceDropPercent": 10, "webhookUrl": "https://example.com/my-webhook" }
With priceDropPercent: 10, a price drop of at least 10% from the previous check alerts; smaller drops, price increases, and layout changes do not. An InStock ↔ OutOfStock flip alerts regardless of the price threshold. The page must expose these fields in structured metadata; if it does not, the result says no-product-data (errorType: "no_product_data"), keeps the previous baseline, and is not charged. CSS selectors, JSON paths and text noise controls are ignored in this mode. Product pages disallowed by robots.txt return a free blocked row with errorType: "robots_disallowed". The product:price meta fallback uses the selected HTTP route: Actor network for direct, VM for vm, and Actor network when auto needs it. backend cannot expose raw meta tags, so use JSON-LD on that route or select another route. Each successful product check uses the existing one page-checked event; there is no product surcharge.
Price monitor for any website
Watch product prices on any online store, or a competitor's pricing page, and get an alert when a price moves or a product goes out of stock. Point a CSS selector at the product box, keep only price and stock words as keywords, and read the old and new price in numericChanges.
{"urls": [{ "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html", "userData": { "selector": ".product_main", "name": "A Light in the Attic" } },{ "url": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html", "userData": { "selector": ".product_main", "name": "Tipping the Velvet" } }],"monitorName": "book-prices","watchKeywords": ["£", "out of stock"],"ignorePatterns": ["\\(\\d+ available\\)"],"outputOnlyChanges": true,"webhookUrl": "https://hooks.slack.com/services/..."}
selector: ".product_main"watches only the product box (title, price, stock), not the "recently viewed" or recommendations around it. On your own stores, use the element around the price, e.g..price,#product-priceor[itemprop=price](right-click the price → Inspect to find it). One selector for all pages also works: set Only watch this part of the page (cssSelector).watchKeywordsmakes a change significant (and alerted) only when a changed line contains a currency sign or "out of stock". Use$,€or the store's own wording ("sold out", "add to cart").ignorePatternsdrops the stock counter ("In stock (22 available)"), so a falling count is not an alert, while "Out of stock" still is.- When a price changes, the row carries
numericChanges, e.g.[{ "before": "£51.77", "after": "£44.10", "context": "£44.10" }], and alerts show "£51.77 → £44.10".
Run it once to save the prices, then add a daily schedule. Each page check costs $0.002 (100 products checked daily ≈ $6 per month), whether the price changed or not.
Watch one field of a public JSON API
Many price, version and status pages are backed by a public JSON URL. Set JSON field to watch (jsonPath) to compare just that value, or set jsonPath per page in user data (it overrides the global one):
{"urls": [{ "url": "https://registry.npmjs.org/express/latest", "userData": { "jsonPath": "$.version", "name": "express version" } },{ "url": "https://api.github.com/repos/nodejs/node/tags", "userData": { "jsonPath": "$[0].name", "name": "latest Node.js tag" } }],"monitorName": "api-fields"}
- Paths use object keys and array indexes only:
$.price,$.items[0].price,$[0].name. Wildcards, filters and expressions are not supported. - Object key order does not count as a change; an object or array value is compared as a whole.
- A successful read costs the usual $0.002 per page check. A missing field, a response that is not JSON, an invalid path, a page that robots.txt disallows or a response over 512 KiB is a free
failedrow, and the saved value is kept for the next run. - Changing the path saves a new baseline instead of reporting a change. JSON pages are read directly with an identified User-Agent; only public URLs that need no login work.
How much does it cost?
| Event | Price |
|---|---|
| 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.
| Monitor | Checks per month | Cost per month |
|---|---|---|
| 1 page, every hour | 720 | $1.44 |
| 1 page, every hour, with screenshots and 10 alerted changes | 720 + 11 screenshots | $1.47 |
| 20 pages, once a day | 600 | $1.20 |
| 100 pages, once a day | 3,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: trueorfalse, and theerrortext 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.notProcessedlists them (count and up to 100 URLs), and the webhook and e-mail are still sent withincomplete: trueanduncheckedPages, so an integration does not read "no alert" as "no changes".
How to use it
- Paste the pages to watch, one URL per line (
example.com/pricingworks 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"}. - Give the monitor a name (runs with the same name compare against each other).
- Optional: set a CSS selector, ignore patterns, keywords, and alerts (e-mail, webhook URL).
- 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.
- 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.
- 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
SUMMARYrecord.
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: falsewith aminorReason(for example "no watched keyword in the changed lines"): reported, but no alertnumericChanges:[{ "before": "$19", "after": "$29", "context": "Pro plan $29/month" }]noiseOnly: trueon anunchangedpage: only dates, times or counters differed (with Ignore dates, times and counters)reorderedOnly: trueon anunchangedpage: 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/removedshow 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 andselectorFallback: trueis set- Locked baseline:
baselineAt,driftedSinceandnewSinceLastRun(alerts fire only when the page differs from what the previous run saw) status: "failed"witherror,errorTypeandconsecutiveFailures(not charged; the baseline is kept)- On
first-check:watchedPreview(the first lines of the watched text) andwatchedLines, so you can see whether your CSS selector picked the right part of the page. After a settings change:reason: "settings-changed" status: "removed"withhttpStatus(404 or 410),removedAtandsignificant: truethe first time (not charged; the baseline is kept). When the page is back, the result carriesrestored: true- Every row has
charged: trueorfalse; successful rows also carryfinalUrlandhttpStatus. 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) andpreviousScreenshotUrl(the "before" image: the last screenshot saved for that page; with a locked baseline, the baseline's screenshot).screenshotErrorif 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.
- Images and other binary files are not compared: an image URL only saves the link as its baseline (and is charged as a page check), so it never reports a change. PDFs and plain-text files are read and compared as text.
- A page that cannot be reached at all (unknown host, blocked, timeout) is reported as
failedand is free; the message can be short, e.g. "target returned HTTP 530" for a host that does not exist. - The text converter can leave out elements such as the heading that repeats the page title (
h1),title,header,navorfooter. When a CSS selector matches nothing in the converted text, the Actor looks for it once more in the page's raw HTML (read from the Actor's own network with the TidyTools User-Agent; skipped when HTTP route isbackendorvm, or inbrowsermode) and the row saysselectorSource: "raw-html". This second look understands tags,#id,.class,[attribute]/[attribute=value], spaces (descendants),>and comma lists;:pseudo-classes,+and~are not supported there and still end asselector-not-found. It sees only the HTML the server sends, not content added later by JavaScript. Text taken from raw HTML is plain (headings keep#, list items-), so if a page's selector switches between the two sources, the next check may report one change. - Very large pages: only about the first 500,000 characters of text per page are kept as the baseline.
FAQ
Does the Actor collect usage data? The Actor sends one anonymous usage counter per run (input type, item count range, outcome) to improve the tool; no URLs, content or account data.
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.
Can I watch two parts of the same page? Yes. List the page twice with different selectors in Pages with per-page settings (for example .price and .stock); each URL + selector pair is its own baseline and its own page check. The same URL with the same selector listed twice is checked once (https://example.com and https://example.com/ count as one).
What happens if my input has a mistake? The run still ends normally and nothing is charged. A line that is not a URL gets its own invalid-input row and the other pages are checked. An empty list, an invalid ignore pattern (regular expression), an invalid e-mail address or a bad proxy setting ends the run with one free invalid-input row, a status message that names the problem, and SUMMARY.status NO_RESULTS.
Is a failed check charged? No. Unreachable or blocked pages, HTTP errors, removed pages (404 / 410) and selectors that match nothing are free; the row says "(not charged)" and has charged: false.
Support
Open an issue in the Issues tab with the URL and your input. Issues are checked regularly.
Found this useful? A short review on the Store helps other users find it.