By use case · Change monitoring
Website change monitoring API for website change detection and page change monitoring tools
The short answer
Website change monitoring means fetching a page on a schedule, storing what it said, and comparing each new capture to the last one so you find out when something you care about moves. To monitor a website for changes you need four pieces: a fetch that renders the page the way a browser would, a normalization step that strips the parts which change on every load, a comparison against your previous snapshot, and an alert plus an archive of the old version. ClawEngine handles the first three by returning typed fields or clean markdown instead of raw HTML, which is what makes the comparison meaningful. The interesting engineering is never fetching. It is deciding what counts as a change, because timestamps, rotating ads, session identifiers and A/B variants will fire an alert every single run if you hash the page as it arrives. Plans start at $39 a month with no free tier.
Clean markdown & JSON · JavaScript rendered · robots.txt respected
Last updated July 2026
Hit Extract to turn this page into clean, LLM-ready data.
robots.txt respected · public data only
Set up a naive page watcher and you get an alert within the hour. Then another. By the end of the day you have forty notifications and not one of them is about anything real. The page carried a rendered timestamp in the footer, the ad slot rotated, the CSRF token was regenerated, and the site put you in a different A/B bucket than last time. Nothing a human would call a change changed, and now nobody reads the alerts. That is how most change monitoring projects die: not from missing a change, but from crying wolf until the channel is muted.
The fix is to stop comparing pages and start comparing meaning. Instead of hashing the HTML, pull the specific fields that matter (the price on a competitor's pricing page, the effective date and section headings on a terms of service document, the availability flag on a product, the version and entries in a changelog, the list of open roles on a careers page) and compare those. Cosmetic churn falls out automatically because you never captured it. ClawEngine returns exactly that: you POST a URL and a schema, the page is rendered server side so client-built content is actually present, and you get back typed JSON or normalized markdown. Hash the typed record, not the response body, and your diff becomes something a person can read.
The second thing teams get wrong is frequency. Every five minutes is the default in most tools and it is almost always the wrong number. A federal register page updates on business days. A vendor's terms of service changes twice a year. A competitor's pricing page might move once a quarter and then three times in a week when they launch a new tier. Match the interval to how fast the page has actually moved in your own history, tier your watchlist, and spend the frequency budget on the ten URLs where hours matter rather than the four hundred where a daily check is generous.
Store a snapshot on every run, not just on change. A timestamped capture of what a page said on a given date is worth more than the alert itself when a vendor claims their refund policy always read that way, when compliance asks what a regulation required last March, or when you need to show a partner exactly when their published price moved. Keep the raw capture and the extracted fields side by side so you can re-run a different extraction later without refetching history you can never get back.
Where this is the wrong tool, plainly: if you want to watch one page, occasionally, and you are not a developer, a dedicated visual change detection tool or a free self-hosted watcher such as changedetection.io will do the job for nothing and take ten minutes to set up. Use it. The API earns its place when you have dozens or thousands of URLs, when you want typed fields rather than a highlighted screenshot, when the pages build themselves in JavaScript, when the results have to land in your own database next to everything else, and when someone will eventually ask you to query the history. We crawl public, permitted pages and respect robots.txt. We do not bypass anti-bot systems, logins, paywalls or CAPTCHAs, so anything behind those is not a source we can monitor for you.
Any URL in LLM-ready data out
robots.txt respected public data only
Why it works
What you get with Change monitoring
Diff meaning, not markup
Compare typed fields you asked for instead of raw HTML. Rotating ads, session tokens and rendered timestamps never enter the comparison, so alerts fire on real edits.
Renders before it compares
Pages that build their content in the browser return complete, so a client-side price or availability flag is part of the snapshot rather than an empty placeholder.
A history you can query
Every run writes a timestamped capture into your own store. What a policy page said on a given date becomes a SQL query rather than a trip to the Wayback Machine.
What it handles
Any URL in, clean structured data out
Point ClawEngine at a public page and it crawls, renders the JavaScript and extracts clean markdown or typed JSON in one call. Define a schema for structured fields, and respect robots.txt and Terms of Service by default.
- Extracts typed fields for semantic diffing
- Renders JavaScript before capturing
- Crawls whole docs and policy trees
- Writes timestamped snapshots you keep
- Normalizes noise out before hashing
- Reads robots.txt and stays on permitted pages
{
"url": "https://example.com/products/atlas",
"title": "Atlas Field Notebook",
"markdown": "# Atlas Field Notebook\n\nDurable...",
"data": {
"name": "Atlas Field Notebook",
"price": 24.00,
"currency": "USD",
"rating": 4.7
},
"links": [ "/products", "/cart" ],
"metadata": { "rendered": true }
}
Why ClawEngine
One API that crawls, renders and extracts
Not a raw HTML dump, not a headless browser fleet to run, and not a brittle parser to maintain. One call crawls a public page, renders its JavaScript and returns clean markdown or typed JSON, built for RAG pipelines and AI agents.
LLM-ready output
Clean markdown or typed JSON with the boilerplate stripped, so the data drops straight into a vector store, a prompt or an agent without a cleanup step.
JavaScript rendered
Each page loads in a real browser environment before extraction, so single-page apps and client-rendered content come back complete, not as an empty shell.
Compliance-first
ClawEngine works on public, permitted data only. It respects robots.txt and site Terms of Service and honors crawl-delay, so responsible scraping is the default.
Code examples
Detect real changes, not page noise
Extract the fields you care about, normalize them, and hash that instead of the response body. Run the same watchlist on a schedule, write one snapshot per check, and alert only when the normalized record differs from the last one.
import hashlib, json, os, requests
BASE = "https://api.clawengine.ai/v1"
headers = {"Authorization": f"Bearer {os.environ['CLAWENGINE_API_KEY']}"}
def capture(url, schema):
r = requests.post(f"{BASE}/extract", headers=headers, timeout=90, json={
"url": url,
"format": "json",
"render": True, # content is built client-side
"schema": schema,
})
r.raise_for_status()
return r.json()["data"]
NOISE = {"session_id", "csrf_token", "rendered_at", "view_count", "ab_variant"}
def fingerprint(data):
# only the fields we actually watch, with volatile keys dropped
clean = {k: v for k, v in data.items() if k not in NOISE}
for k, v in clean.items():
if isinstance(v, str):
clean[k] = " ".join(v.split()) # collapse whitespace
if isinstance(v, list):
clean[k] = sorted(v) # order is not meaningful
blob = json.dumps(clean, sort_keys=True, separators=(",", ":"))
return hashlib.sha256(blob.encode()).hexdigest(), clean
url = "https://example.com/pricing"
data = capture(url, {
"plan_names": "string[]",
"plan_prices": "number[]",
"effective_date": "string",
})
digest, clean = fingerprint(data)
prev = load_snapshot(url) # your store: Postgres, S3, whatever
if prev is None:
save_snapshot(url, digest, clean) # first run: baseline only, no alert
elif prev["digest"] != digest:
changed = {k: (prev["clean"].get(k), clean[k])
for k in clean if prev["clean"].get(k) != clean[k]}
save_snapshot(url, digest, clean) # append, never overwrite
notify(url, changed) # old value -> new value, per field
# cron: run the fast tier hourly, the rest once a day
# 0 * * * * python sweep.py --tier hourly
# 15 6 * * * python sweep.py --tier daily
import datetime, os, requests
BASE = "https://api.clawengine.ai/v1"
headers = {"Authorization": f"Bearer {os.environ['CLAWENGINE_API_KEY']}"}
WATCHLIST = [
# tier the list by how fast the page really moves, not by habit
{"url": "https://competitor.example/pricing", "tier": "hourly",
"schema": {"plan_names": "string[]", "plan_prices": "number[]"}},
{"url": "https://vendor.example/legal/terms", "tier": "daily",
"schema": {"effective_date": "string", "section_titles": "string[]"}},
{"url": "https://supplier.example/sku/44120", "tier": "hourly",
"schema": {"price": "number", "in_stock": "boolean"}},
{"url": "https://agency.example/rules/2026-07", "tier": "daily",
"schema": {"title": "string", "last_updated": "string", "status": "string"}},
]
def sweep(tier):
now = datetime.datetime.now(datetime.timezone.utc).isoformat()
for item in WATCHLIST:
if item["tier"] != tier:
continue
try:
r = requests.post(f"{BASE}/extract", headers=headers, timeout=90, json={
"url": item["url"], "format": "json",
"render": True, "schema": item["schema"],
})
if r.status_code == 404:
write_diff(item["url"], now, status="gone", delta=None)
continue # a page vanishing is an event too
r.raise_for_status()
digest, clean = fingerprint(r.json()["data"])
except requests.RequestException as e:
record_failure(item["url"], now, str(e)) # alert on 3 in a row, not 1
continue
prev = load_snapshot(item["url"])
if prev and prev["digest"] != digest:
write_diff(item["url"], now, status="changed",
delta={k: (prev["clean"].get(k), clean[k])
for k in clean if prev["clean"].get(k) != clean[k]})
save_snapshot(item["url"], digest, clean, checked_at=now) # every run
import crypto from "node:crypto";
const BASE = "https://api.clawengine.ai/v1";
const headers = {
Authorization: `Bearer ${process.env.CLAWENGINE_API_KEY}`,
"Content-Type": "application/json",
};
// one call walks the whole tree instead of you writing a frontier queue
const res = await fetch(`${BASE}/crawl`, {
method: "POST",
headers,
body: JSON.stringify({
url: "https://vendor.example/docs",
include: ["/docs/*", "/legal/*"], // scope it, or you crawl the blog too
max_pages: 800,
format: "json",
schema: { title: "string", body_text: "string", last_updated: "string" },
}),
});
const job = await res.json();
// markdown-level normalization: kill the bits that move on every render
const normalize = (s = "") =>
s.replace(/\b20\d{2}-\d{2}-\d{2}T[\d:.]+Z?\b/g, "") // ISO timestamps
.replace(/\?(utm_[^"\s]+|v=\d+)/g, "") // cache busters, tracking
.replace(/\s+/g, " ")
.trim();
const hash = (s) => crypto.createHash("sha256").update(s).digest("hex");
const previous = await loadPreviousRun(); // { url: digest } from the last crawl
const added = [], changed = [], removed = new Set(Object.keys(previous));
for (const page of job.pages) {
const digest = hash(normalize(page.data.title) + "|" + normalize(page.data.body_text));
removed.delete(page.url);
if (!(page.url in previous)) added.push(page.url);
else if (previous[page.url] !== digest) changed.push(page.url);
await saveSnapshot(page.url, digest, page.data); // keep the dated capture
}
console.log({ added, changed, removed: [...removed], checked: job.pages.length });
People also ask
Website change monitoring API: the questions buyers ask
How do I monitor a website for changes?
Fetch the page on a schedule, save what it returned, and compare each capture to the previous one. The part people skip is normalization: strip timestamps, session identifiers, rotating ad slots and tracking parameters before you compare, or every run looks like a change. Extracting typed fields instead of comparing raw HTML does that for you, because the noisy elements are never captured in the first place.
How do I get notified when a web page changes?
Run the check on a schedule, compare the new capture to your stored snapshot, and fire a webhook, email or Slack message only when the comparison differs. Send the actual delta in the notification (old value, new value, field name, timestamp) rather than a bare "page changed" line. Alerts people can act on without opening the page are the ones that stay unmuted after week two.
What is the best website change monitoring tool?
For one page and a non-technical user, a hosted visual watcher or a self-hosted tool like changedetection.io is the best answer, and it is free or nearly free. For many pages, typed fields, JavaScript-rendered content and history you can query in SQL, an API-based approach fits better because the results live in your own database. Pick by page count and by whether you need fields or a screenshot.
How often should I check a page for changes?
Match the interval to how fast the page actually moves, not to how fast your tool allows. Terms of service and policy pages justify daily or weekly. Docs and changelogs suit daily. Competitor pricing and availability pages often warrant hourly, and job boards or funding announcements sit somewhere between. Look at your own change history after a month and retune, because most watchlists are overchecked on the boring pages.
Can I monitor a page that requires JavaScript?
Yes, provided the page is public. A plain HTTP fetch on a single page app returns an empty shell, so a naive watcher either sees no content or reports a change every time the shell shifts. Setting render to true runs the page in a real browser first, so the content the user sees is what gets compared. Pages behind a login or a paywall are out of scope.
How much does website change monitoring cost?
Self-hosted watchers cost you a small server and your time. Hosted single-page tools typically run from nothing up to a few tens of dollars a month. ClawEngine starts at $39 a month on Hobby, $99 on Startup and $399 on Scale, with no free tier, and the meaningful cost driver is checks per day multiplied by URLs. Tiering the watchlist by how fast each page moves is the main lever.
Good questions
Questions about Change monitoring
Explore more
More ways to turn the web into data with ClawEngine
Stop wrangling raw HTML. Get LLM-ready data.
Point ClawEngine at a public page and one call crawls, renders the JavaScript and extracts clean markdown or typed JSON, ready for your RAG pipeline or AI agent. Public, permitted data only.
Crawl · render JS · extract markdown & JSON · robots.txt respected, public data only