{"name":"website-change-monitor","id":"sfoln/website-change-monitor","title":"Website Change Monitor – Text Diff Alerts","description":"Monitor web pages for changes: each run compares a page's text (or a CSS-selected part) with the last check and returns first seen, unchanged or changed with a line diff, similarity and added/removed lines. Ignore noisy text, add AI change summaries. $1 per 1,000 checks.","version":"0.1","status":"ready","family":{"id":"ai-agent-web-toolkit","name":"Web toolkit for agents","description":"Web search for retrieval, pages and sites converted to Markdown, AI extraction to JSON, URL metadata and safety checks, sitemaps, feeds, change monitoring and academic paper search.","actors":11},"categories":["DEVELOPER_TOOLS","AUTOMATION","SEO_TOOLS"],"availability":"on_request","seoTitle":"Website Change Monitor – Page Change Detection API","seoDescription":"Detect changes on any web page: text diff, similarity, added and removed lines, CSS selectors, ignore patterns, AI summaries. $1 per 1,000 checks.","summary":"Monitor web pages for changes and get a clear answer per URL on every run: first_seen, unchanged or changed — with a unified text diff, a similarity score, added and removed lines, and optionally an AI summary of what changed. Watch a whole page's main text or just the part you care about with a CSS selector (prices, job lists, terms, release notes), and ignore noise such as timestamps and counters. Built for competitor and pricing intelligence, compliance and policy tracking, procurement and job-board watching, SEO, and AI agents that need to know \"has this page changed since yesterday?\".","pricing":{"model":"pay-per-event","currency":"USD","billedBy":"Apify","freePlanMaxItemsPerRun":10,"events":[{"name":"page-check","title":"Page check","description":"Charged once per URL checked: fetched, compared with its last snapshot and reported as first seen, unchanged or changed with a diff.","priceUsd":0.001},{"name":"change-summary","title":"AI change summary","description":"Charged once per changed page for which the AI summary of the change (summary and significance) was generated. Paid plans only.","priceUsd":0.003,"paidPlanOnly":true}]},"input":{"description":"Pages to check. Each run compares every page with its snapshot from the previous run (kept in a named key-value store in your account) and returns one record per URL. Schedule the Actor to get change alerts.","required":["urls"],"fields":[{"name":"urls","title":"URLs","type":"array","required":true,"description":"Pages to monitor, one per line (public http(s) URLs). The first check of a URL saves its baseline. Accounts on the Apify free plan can process up to 10 URLs per run.","prefill":["https://example.com/"],"editor":"stringList"},{"name":"selector","title":"CSS selector","type":"string","required":false,"description":"Watch only the elements matching this CSS selector (e.g. #pricing, .job-list li, table.prices tr). Empty: the page's main text (navigation, footer and scripts left out). Each selector keeps its own snapshot of a page.","editor":"textfield"},{"name":"ignorePatterns","title":"Ignore patterns","type":"array","required":false,"description":"Regular expressions (case-insensitive), one per line: matching text is removed from each line before comparing, e.g. Last updated: .* or \\d+ views. Changing them later applies to the stored snapshot too. Patterns that backtrack catastrophically, such as (a+)+ or (\\w|\\d)+, are refused.","editor":"stringList"},{"name":"ignoreNumbers","title":"Ignore numbers","type":"boolean","required":false,"description":"Treat all numbers as equal (counters, timestamps, prices), so only changes in wording count.","default":false},{"name":"summarizeChanges","title":"AI change summary (paid add-on)","type":"boolean","required":false,"description":"For changed pages, add a one-paragraph AI summary of what changed and its significance (minor, moderate, major). Charged per summary (change-summary); paid Apify plans only.","default":false},{"name":"diffContextLines","title":"Diff context lines","type":"integer","required":false,"description":"Unchanged lines shown around each change in the unified diff.","default":2,"minimum":0,"maximum":10},{"name":"maxDiffChars","title":"Max diff length","type":"integer","required":false,"description":"Characters of unified diff per page; a longer diff is cut (diffTruncated: true).","default":5000,"minimum":500,"maximum":100000},{"name":"excerptChars","title":"Text excerpt length","type":"integer","required":false,"description":"Characters of the page's current text in textExcerpt (0 = none).","default":1000,"minimum":0,"maximum":20000},{"name":"includeText","title":"Include full text","type":"boolean","required":false,"description":"Add the full normalized page text (up to 200,000 characters) to each record.","default":false},{"name":"storeName","title":"Snapshot store name","type":"string","required":false,"description":"Named key-value store for the snapshots (letters, digits, hyphens). Default: website-change-monitor-memory. Use different names to keep separate monitors of the same pages apart; delete a record (or the store) to reset a baseline.","editor":"textfield"},{"name":"maxUrls","title":"Max URLs","type":"integer","required":false,"description":"Safety cap on URLs in this run; the rest are ignored and counted as inputItemsDropped in the OUTPUT record.","default":500,"minimum":1,"maximum":5000},{"name":"concurrency","title":"Concurrency","type":"integer","required":false,"description":"Pages checked in parallel.","default":4,"minimum":1,"maximum":10}]},"exampleInput":{"urls":["https://example.com/"]},"outputFields":[{"name":"input","type":"string | object","title":"Input","description":"The URL this record corresponds to."},{"name":"status","type":"string","title":"Status","description":"ok | not_found | error | skipped_invalid | skipped_budget | skipped_free_plan | skipped_unmetered","example":"ok"},{"name":"charged","type":"boolean","title":"Charged","description":"Whether this record incurred a pay-per-event charge."},{"name":"chargedEvent","type":"string","title":"Charged event","description":"Pay-per-event event charged for this record (present only when charged)."},{"name":"chargedCount","type":"integer","title":"Events charged","description":"Events actually charged when the charge came back short of the requested count (present only then; a warning explains it)."},{"name":"source","type":"string","title":"Source","description":"Upstream data source."},{"name":"fetchedAt","type":"string","title":"Fetched at","description":"ISO timestamp."},{"name":"error","type":"object","title":"Error","description":"{ code, message, provider?, status? } when status is not ok. Codes set by the runtime: budget_exhausted, free_plan_limit, unmetered, aborted, charge_failed, record_too_large, invalid_record, dataset_push_failed, memory_unavailable; fetch codes: http_<status>, invalid_url, blocked_url, dns_not_found, network, tls_error, timeout, too_many_redirects, unexpected_type, too_large; this Actor: selector_not_found, no_text, pattern_too_slow."},{"name":"warnings","type":"array","title":"Warnings","description":"Notes, e.g. a page cut at 5 MB or a skipped AI summary."},{"name":"url","type":"string","title":"URL","description":"The monitored URL."},{"name":"finalUrl","type":"string","title":"Final URL","description":"The URL that answered, after redirects."},{"name":"httpStatus","type":"integer","title":"HTTP status","description":"Status of the final response."},{"name":"title","type":"string | null","title":"Page title","description":"The page's <title>."},{"name":"contentType","type":"string | null","title":"Content type","description":"Declared media type."},{"name":"selector","type":"string | null","title":"Selector","description":"The CSS selector watched (null: the page's main text)."},{"name":"selectorMatches","type":"integer | null","title":"Selector matches","description":"Elements the selector matched."},{"name":"changeStatus","type":"string","title":"Change status","description":"first_seen (baseline saved) | unchanged | changed | error (the page could not be checked; not charged)."},{"name":"changed","type":"boolean","title":"Changed","description":"True when the page changed since the previous check."},{"name":"similarity","type":"number | null","title":"Similarity","description":"0–1 share of unchanged lines (1 = identical); null on the first check."},{"name":"addedLines","type":"integer","title":"Added lines","description":"Lines added since the previous check."},{"name":"removedLines","type":"integer","title":"Removed lines","description":"Lines removed since the previous check."},{"name":"diff","type":"string | null","title":"Diff","description":"Unified diff of the page text (- removed, + added), at most maxDiffChars."},{"name":"diffTruncated","type":"boolean","title":"Diff truncated","description":"The diff was cut at maxDiffChars."},{"name":"addedSample","type":"array","title":"Added lines (sample)","description":"Up to 10 added lines."},{"name":"removedSample","type":"array","title":"Removed lines (sample)","description":"Up to 10 removed lines."},{"name":"textExcerpt","type":"string | null","title":"Text excerpt","description":"The start of the page's current text (excerptChars)."},{"name":"textLength","type":"integer","title":"Text length","description":"Characters of normalized text compared."},{"name":"lineCount","type":"integer","title":"Lines","description":"Lines of normalized text."},{"name":"textTruncated","type":"boolean","title":"Text truncated","description":"The page or its text was cut (5 MB / 200,000 characters)."},{"name":"contentHash","type":"string","title":"Content hash","description":"SHA-256 of the compared text (after ignore patterns)."},{"name":"previousHash","type":"string | null","title":"Previous hash","description":"SHA-256 of the previous text, compared the same way."},{"name":"previousCheckedAt","type":"string | null","title":"Previous check","description":"When the snapshot compared with was taken."},{"name":"firstSeenAt","type":"string","title":"First seen","description":"When the page was first checked."},{"name":"lastChangedAt","type":"string | null","title":"Last changed","description":"The last check that found a change."},{"name":"checkedAt","type":"string","title":"Checked at","description":"This check."},{"name":"summary","type":"string | null","title":"AI summary","description":"What changed, in a few sentences (summarizeChanges, paid add-on)."},{"name":"significance","type":"string | null","title":"Significance","description":"minor | moderate | major (AI summary)."},{"name":"summaryCharged","type":"boolean","title":"Summary charged","description":"The change-summary add-on was charged for this page."},{"name":"text","type":"string","title":"Text","description":"The full normalized text (includeText)."}],"outputExample":{"input":"https://shop.example.com/pricing","url":"https://shop.example.com/pricing","finalUrl":"https://shop.example.com/pricing","httpStatus":200,"title":"Pricing","contentType":"text/html","selector":null,"selectorMatches":null,"changeStatus":"changed","changed":true,"similarity":0.75,"addedLines":1,"removedLines":1,"diff":"--- previous\t2026-10-13T12:00:00.000Z\n+++ current\t2026-10-14T12:00:00.000Z\n@@ -1,4 +1,4 @@\n Pricing\n Simple plans for every team, billed monthly or yearly.\n-Starter | $10\n+Starter | $12\n Pro | $49","diffTruncated":false,"addedSample":["Starter | $12"],"removedSample":["Starter | $10"],"textExcerpt":"Pricing\nSimple plans for every team, billed monthly or yearly.\nStarter | $12\nPro | $49","textLength":86,"lineCount":4,"textTruncated":false,"contentHash":"4f1c…","previousHash":"9a0b…","previousCheckedAt":"2026-10-13T12:00:00.000Z","firstSeenAt":"2026-10-01T12:00:00.000Z","lastChangedAt":"2026-10-14T12:00:00.000Z","checkedAt":"2026-10-14T12:00:00.000Z","summary":"The Starter plan price rose from $10 to $12 per month; the Pro plan is unchanged.","significance":"moderate","summaryCharged":true,"status":"ok","charged":true,"chargedEvent":"page-check","source":"website","fetchedAt":"2026-10-14T12:00:00.000Z"},"faq":[{"question":"Where are the snapshots stored?","answer":"In a named key-value store in your own Apify account (website-change-monitor-memory unless you set storeName), one record per URL and selector. Named stores are kept between runs; delete a record or the whole store to reset the baselines."},{"question":"How do I get alerts?","answer":"Schedule the Actor (hourly, daily…) and add a webhook or a Make/Zapier/n8n integration that filters the dataset on changed = true."},{"question":"Does it render JavaScript?","answer":"No. It compares the HTML the server sends. Pages that build their content in the browser return no text (status error, not charged); point the Actor at the page's JSON API or a server-rendered URL instead."},{"question":"How do I stop false alarms from timestamps and counters?","answer":"Add ignorePatterns such as Last updated: .* or \\d+ views, or turn on ignoreNumbers. Patterns are applied to both the stored snapshot and the new text, so you can tune them at any time."}],"mcpExamplePrompt":"Use website-change-monitor to check https://example.com/ for changes since the last check and tell me what changed.","related":["url-to-markdown-summary","url-metadata","url-safety-check","domain-intelligence","seo-competitor-snapshot","onpage-seo-audit","brand-mentions-monitor","substack-scraper"],"urls":{"site":"https://www.sfoln.com/actors/website-change-monitor/","siteJson":"https://www.sfoln.com/actors/website-change-monitor.json","siteMarkdown":"https://www.sfoln.com/actors/website-change-monitor.md","runSync":"https://api.apify.com/v2/actors/sfoln~website-change-monitor/run-sync-get-dataset-items","runAsync":"https://api.apify.com/v2/actors/sfoln~website-change-monitor/runs","mcp":"https://mcp.apify.com?tools=sfoln/website-change-monitor","requestAccess":"mailto:contact@sfoln.com?subject=Access%20request%3A%20Website%20Change%20Monitor%20%E2%80%93%20Text%20Diff%20Alerts%20(sfoln%2Fwebsite-change-monitor)&body=Please%20publish%20website-change-monitor.%20What%20we%20plan%20to%20use%20it%20for%3A"},"publisher":{"name":"SFOLN LLC","apifyUsername":"sfoln","url":"https://www.sfoln.com","apifyProfile":"https://apify.com/sfoln","email":"contact@sfoln.com"},"generatedAt":"2026-10-22T04:28:58.477Z"}