Website Change Monitor: New Items & Telegram Alerts
Pricing
from $1.00 / 1,000 page checks
Website Change Monitor: New Items & Telegram Alerts
Monitor web pages and get Telegram, Slack or webhook alerts only on real changes. Watch a CSS selector per page, or get only new items from job boards, feeds and tenders. Errors never count as changes. No browser: fast and cheap. You pay only for pages checked successfully.
Pricing
from $1.00 / 1,000 page checks
Rating
0.0
(0)
Developer
Hafid Gougua
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Reliable Page Change Monitor
This website change monitor watches web pages and sends a Telegram, Slack or webhook alert only when the content you care about really changes: page change detection that ignores noise. Point it at a CSS selector, choose "new items only" for feeds and listings, and stop getting alerts for reordered lists, whitespace edits or a site that was down for a minute.
Step-by-step tutorial
New to website monitoring or Telegram bots? Read the full setup guide (about 15 minutes, no code): How to Get Telegram Alerts When Any Website Changes
Who it is for
- Job seekers and recruiters: get the new postings on a careers page or job board, not the whole page every time it reshuffles.
- E-commerce and pricing teams: watch a competitor's price or stock block (
#price,.availability) and nothing else. - Developers: follow changelogs, API docs and release notes.
- Ops and support teams: watch public status pages for new incidents.
- Procurement and sales: be the first to see new public tenders and calls for proposals.
Why it is reliable
- New items only (
newItemsmode): with a CSS selector, every matched element is one item, however many lines it has (shown on one line in alerts); without one, every line is an item. You are alerted only about items never seen before. Reordering, items dropping off the bottom or coming back do not trigger alerts. - A CSS selector per page: monitor just the price, the job list or the incident list. Ads, dates and counters elsewhere on the page are ignored.
- Errors are never changes: an HTTP 500, a timeout, a block page or a missing selector is reported as an error status. The saved version stays untouched, so you never get a "page changed" alert followed by a "changed back" alert.
- Retries: server errors and network errors are retried once; notifications are retried up to 2 more times in the same run (network errors, 5xx, 429 with
Retry-After). If every channel still fails, the alert is retried on the next run, and never sent twice. - Whitespace-insensitive: extra spaces and blank lines are normalized away.
- No browser: plain HTTP requests, so runs are fast (seconds) and cheap (256 MB memory).
- You never pay for failures: only pages that were fetched and compared are billed.
Tested on the Apify platform: 47 consecutive hourly scheduled runs over 48 hours, 10 pages each, with no failed run.
Example Telegram alert (newItems mode)
New items: BBC News headlines — https://www.bbc.com/newsChecked at: 2026-10-27T06:00:24.756Z+ Israel heads to polls for pivotal election defined by security and democracy+ New Zealand election 2026: What you need to know
Long alerts stay within Telegram's 4,096-character limit (Slack: 3,000). Lines are never cut in the middle; the message ends with …and N more new items when not everything fits. The webhook always receives every item as JSON.
Input
| Field | Type | Default | Description |
|---|---|---|---|
pages | array of objects | Pages to monitor, each { url, cssSelector?, label?, compareMode? }. | |
urls | array of strings | [] | Pages that share the cssSelector below (kept for older tasks). |
cssSelector | string | "" | Selector for every entry of urls. Empty means the whole <body> text. |
compareMode | text or newItems | text | Default mode for pages that do not set their own. |
webhookUrl | string (secret) | Receives a JSON POST per change. | |
slackWebhookUrl | string (secret) | Slack incoming webhook. | |
telegramBotToken | string (secret) | Telegram bot token (from @BotFather). | |
telegramChatId | string | Telegram chat that receives the alerts. | |
notifyOnError | boolean | false | Also alert when a page cannot be checked. |
requestTimeoutSecs | integer | 30 | Per-request timeout (1–300). |
stateStore | key-value store | Recommended. The store that keeps the last version of each page between runs. See Save state between runs. | |
stateStoreName | string | page-change-monitor-state | Fallback when no stateStore is selected: a named key-value store for the state. |
| Up to 50 pages per run. The same URL + selector pair is checked once. |
{"pages": [{ "url": "https://news.ycombinator.com/newest", "cssSelector": ".titleline", "label": "HN newest", "compareMode": "newItems" },{ "url": "https://www.rfc-editor.org/rfc/rfc2606.html", "cssSelector": "pre.newpage", "label": "RFC 2606" }],"telegramBotToken": "<your bot token>","telegramChatId": "<your chat id>"}
Save state between runs
Change detection needs the previous version of each page. Give the Actor a key-value store to keep it in:
- In Apify Console open Storage → Key-value stores and click Create new. Give it a name, for example
my-price-monitor. - In this Actor's input (or your task), open State store, click Select, and choose that store.
- Save and run. The first run records a baseline; later runs alert on changes.
Use one store per independent monitor (for example one per task). Without a selected store the Actor falls back to the named store in stateStoreName. If the platform refuses access to it (for example because a store of that name already exists in your account from another tool), the run still succeeds and writes every page to the dataset, but:
- every page is a
BASELINEand nothing is saved for the next run, - no
page-checkis billed and no alert is sent, - each dataset item has
stateWarning:State is not saved between runs. Select a key-value store in the 'stateStore' input to enable change detection.The same warning is in the run log.
Compare modes
text: a line diff of the monitored text, added lines (+) first, then removed lines (-). Best for a price block, terms of service, a single document.newItems: alerts list only lines never seen before, in any order. Removals or reordering alone giveCHANGED_NO_NEW_ITEMSwith no alert. Best for job boards, feeds, tenders, incident lists. Up to 5,000 item fingerprints are kept per page. Switching a page fromtexttonewItemsrecords a silent baseline first, so you are not flooded.
Statuses
| Status | Meaning | Billed | Alert |
|---|---|---|---|
BASELINE | First check of this URL + selector; version saved. | Yes | No |
UNCHANGED | Same content as last time. | Yes | No |
CHANGED | Content changed and the alert was delivered (or no channel is set). | Yes | Yes |
CHANGED_NO_NEW_ITEMS | newItems mode: only removals or reordering. | Yes | No |
NOTIFY_FAILED | Content changed but every channel failed after retries. Retried next run. | No | Retried |
SELECTOR_MISSING | The selector matched no text. | No | If notifyOnError |
HTTP_ERROR | 4xx/5xx or network error. | No | If notifyOnError |
TIMEOUT | The request timed out twice. | No | If notifyOnError |
BLOCKED | 401, 403, 429 or a CAPTCHA / bot challenge. Not bypassed. | No | If notifyOnError |
Only the error statuses leave the saved version untouched, so the next successful check compares against the last good content.
Output
One dataset item per page per run. This is the first run of the default input:
{"url": "https://www.rfc-editor.org/rfc/rfc2606.html","label": "RFC 2606","selector": "pre.newpage","compareMode": "text","status": "BASELINE","checkedAt": "2026-10-28T21:52:03.365Z","changed": false,"hash": "4463f85dbea3cbd2ad28d34e68355ea98040640887fa3c9adef807acb8c139d5","diffPreview": null,"addedCount": 0,"removedCount": 0,"httpStatus": 200,"errorMessage": null,"stateWarning": null}
On a change, changed is true, diffPreview holds the lines shown in the alert, and addedCount / removedCount give the counts.
For every change the webhook receives a JSON POST with type (PAGE_CHANGED), url, label, status, compareMode, checkedAt, diffPreview, added, removed, totalAdded, totalRemoved, addedTruncated and removedTruncated. added and removed hold at most 500 entries each; totalAdded / totalRemoved give the real counts. In newItems mode, added holds the new items. Errors send "type": "PAGE_ERROR" with errorMessage.
Pricing
You pay $1.00 per 1,000 successful page checks (one page-check event per page fetched and compared), plus Apify's standard run-start fee ($0.00005 per run). Alerts are free. Failed checks (HTTP_ERROR, TIMEOUT, BLOCKED, SELECTOR_MISSING, NOTIFY_FAILED) are free.
| You monitor, every hour for 30 days | Checks | Monthly cost |
|---|---|---|
| 1 page | 720 | about $0.76 ($0.72 in checks) |
| 10 pages | 7,200 | about $7.24 |
| 50 pages | 36,000 | about $36.04 |
| 100 pages (two tasks of 50) | 72,000 | about $72.07 |
Checking every 6 hours instead of every hour costs one sixth. If a run reaches your maximum cost per run, it stops cleanly: the pages already checked are saved, the rest keep their previous version and are checked next run.
Scheduling
- On this Actor's page click Create task. Fill in the pages and notification channels, then Save.
- Select a State store in the task input (see Save state between runs).
- Open Schedules → Create new, pick a frequency (for example hourly,
0 * * * *) and add the task under Actors and tasks. - The first run records a baseline without alerts; later runs alert only on changes.
Edit task input as a whole. If you change a task's input through the API, send the full input object, not just the field you changed. A partial input replaces the saved one and can drop your pages, selectors or notification settings. Keep the same
stateStore(orstateStoreName), or the monitor starts over from a new baseline.
Limitations
- No JavaScript. The Actor reads the HTML the server sends. Content rendered in the browser by JavaScript is not seen; pick a selector that exists in the page source (View Source, not DevTools).
- No login. Pages behind a login, a paywall or cookies are not supported.
- No bypassing. Sites that block automated requests (403, 429, CAPTCHA, bot challenges) are reported as
BLOCKEDand are not retried or circumvented. newItemsworks line by line: an item spanning several lines counts as several items. Choose a selector that gives one line per item.textdiffs use the first 20,000 characters of the monitored text; the change detection hash covers the full text.
Privacy and responsible use
- The Actor stores only the normalized text of what you monitor (the selector's text or the page body), its hash and item fingerprints, in your own key-value store. No cookies, screenshots or full HTML are kept.
- It sends ordinary HTTP requests and does not bypass any protection.
- You are responsible for making sure that monitoring a site complies with its terms of service and robots.txt, and with applicable law. Avoid monitoring pages that contain personal data.