[Go to site: main page, start]

Skip to main content
Context.dev’s Monitors API watches a page, a sitemap, or extracted structured data on a schedule you set, compares each run against a baseline, and can send signed webhooks when something changes or after every completed run. You create a monitor once; Context.dev handles the crawling, diffing, judging, and retrying in the background.

Integrate Context.dev's Monitors API in your app

Open in Cursor

Prerequisites

  • A Context.dev API key. Sign up at context.dev/signup, copy the key from the dashboard (prefix ctxt_secret_), and export it:
  • An SDK (optional). Install for your language, or skip the install and call directly with curl:

Create a monitor

A monitor is defined by four things: a target (what to watch), a change_detection strategy (how to compare), a schedule (how often), and an optional webhook (where to notify). This creates a monitor that checks a pricing page every 6 hours:
Management calls are free; you pay per run: 1 credit for page & sitemap checks, 10 for semantic extract The monitor runs immediately after creation to capture its initial baseline: the snapshot every later run is compared against. The response includes the generated webhook signing secret; store it, you’ll need it to verify deliveries:
sample response

Request parameters

Pick a target

Each target type pairs with a supported detection strategy. Supported combinations: page + exact, page + semantic, sitemap + exact, and extract + semantic. Unsupported pairs (for example sitemap + semantic) are rejected with a 400.

Page: did this page’s text change?

Watches a single URL and diffs the visible page text. Whitespace is normalized by default (normalize_whitespace: true).

Page + semantic: alert only on changes you care about

Add target.instructions — a plain-language goal describing which page changes matter — and Context.dev judges each confirmed diff against that goal, so ticker widgets, “as of” timestamps, and rotating testimonials stay quiet while a real edit fires. When instructions is set and you omit change_detection, semantic detection is inferred; passing change_detection: { type: "exact" } alongside instructions is rejected, and semantic page detection without instructions is rejected too.
Under the hood, a semantic page run compares the current page against the baseline, separates stable content from volatile regions (counters, timestamps, ticker text), re-observes the page in the same run to confirm the diff is real, and only then asks the judge whether the stable change matches your instructions. Small numeric drift on values you didn’t ask about is ignored; watched numeric changes (for example a price moving from $29 to $49) are promoted even when the delta is small. Tune sensitivity with change_detection.confidence_threshold (0–1, default 0.75) — raise it to only get notified about changes the judge is more certain matter.

Sitemap: were URLs added or removed?

Watches a sitemap for URL additions and removals, ideal for catching new blog posts, product pages, or docs. URLs are normalized and scoped to the monitored site and its subdomains; on a detected difference the sitemap is re-fetched within the same run and only URLs both observations agree on are reported, suppressing transient crawl flaps.
include / exclude accept URL path patterns, and max_urls caps tracking at up to 10,000 URLs (default 5,000).

Extract: did the data I care about change?

Watches the meaning of a site, not its markup. A crawl guided by your instructions (and optional JSON schema, the same shape the Extract API uses) selects up to max_pages relevant pages; each run re-checks exactly those pages and judges confirmed changes against your instructions, so a reworded paragraph doesn’t fire, but a new pricing tier does. The schema does three things: it steers which pages get selected for tracking, it gives the change judge extra context on which changes matter (alongside your instructions), and it defines the shape of the data snapshot on the monitor’s baseline (refreshed by the re-discovery crawl, at most about once a day). It is not a response format for alerts — change events and webhook payloads always contain diffs, summaries, and evidence excerpts, never data shaped by your schema. Skip it and a general summary + key-points schema is used.
Raise confidence_threshold (0–1, default 0.75) to only get notified about changes the judge is more certain matter. The tracked page set is refreshed by a periodic re-discovery crawl (at most about once a day).

Receive webhooks

Context.dev delivers two webhook events. Subscribe to either or both by setting webhook.events when you create or update a monitor. Each subscribed event fires independently, so a change-run with both events subscribed produces two deliveries — one per event — with matching data.change records.

Choose which events to receive

webhook.events is a list. When you create a webhook, omitting it defaults to ["change.detected"] for backward compatibility. When you update an existing webhook, omitting events preserves its current subscription; send the list explicitly to change it.

change.detected payload

Sent after a run detects a change. data.change is the full change record — the same one returned by GET /monitors/changes/{change_id}.
change.detected payload

run.completed payload

Sent after every completed run when your monitor subscribes to run.completed. data.run is a snapshot of the run at delivery time. data.change is the same full change record delivered by change.detected, or null when the run found no change (including baseline runs, where baseline_created is true).
run.completed payload — no change
data.run doesn’t include credits_charged — billing settles after delivery. Fetch the run via GET /monitors/{monitor_id}/runs for the final billing record.

Verify the signature

Every delivery includes an X-Context-Signature: t=<unix>,v1=<hmac> header, where the HMAC is SHA-256 over "{t}.{rawRequestBody}" keyed by your monitor’s webhook secret. Recompute it with a constant-time compare and reject stale timestamps to prevent replays:
Every delivery also sets an X-Context-Event header (change.detected or run.completed) so you can route events without parsing the body first, and an X-Context-Id header that matches the payload’s top-level id.
For the full payload schemas, see the change.detected reference and the run.completed reference. Type-specific change fields include text diffs for exact page monitors, added and removed URLs for sitemap monitors, and confidence plus evidence for semantic extract monitors.

Inspect delivery status

Each monitor run records the outcome of every webhook it attempted, so you can debug misbehaving endpoints without wiring up your own logs. The run object returned by GET /monitors/{monitor_id}/runs (and GET /monitors/runs) includes a webhook_deliveries array — one entry per subscribed event that fired for that run:
status is one of: event_id matches the X-Context-Id header on the delivery, so you can correlate a run with the exact request your server received. webhook_deliveries is omitted when no webhook was attempted, including runs that predate delivery tracking.
The legacy top-level webhook_delivery field is still returned for backward compatibility. It contains the change.detected attempt when present; otherwise it contains the run’s sole attempted delivery, such as run.completed for a monitor subscribed only to that event. It is deprecated — new integrations should read webhook_deliveries.

Track consecutive delivery failures

Beyond per-run delivery status, the monitor object itself carries a rolling health signal: webhook_failure counts consecutive delivery-attempting runs with at least one failed delivery so you can surface a broken endpoint in your own dashboard. Runs that attempt no webhook leave the streak unchanged.
  • consecutive_failures — number of consecutive delivery-attempting runs whose webhooks did not fully succeed. When a run delivers multiple subscribed events, a single failure among them advances the counter by one.
  • last_status — outcome of the most recent failed delivery: rejected (non-2xx response), failed (no HTTP response), or skipped_unsafe_url (the URL failed the public-endpoint safety check).
  • last_message — human-readable description of the most recent failure.
  • last_failed_at — ISO timestamp of the last failed attempt.
webhook_failure is null when deliveries are healthy or no webhook is configured. It clears after the next run that attempts at least one webhook and delivers every attempt successfully, and resets when you change or remove the webhook URL via PATCH /monitors/{monitor_id}.

Delivery retries

Every webhook delivery is retried on network errors, 5xx responses, and 429 rate-limit responses. When the receiver returns a numeric Retry-After header, Context.dev waits that long before the next attempt (capped at 10 seconds). If every attempt fails, the run’s webhook_deliveries[].status and the monitor’s webhook_failure record the outcome.

Get notified when your endpoint breaks

Once consecutive_failures reaches 3, Context.dev emails every user in your organization to flag the broken endpoint. You get one email per streak — a run that attempts at least one webhook and delivers every attempt successfully re-arms the notification for the next episode. When several monitors deliver to the same URL, the notification is coalesced: one email covers the endpoint for 24 hours instead of one per monitor.

Read changes over the API

No webhook? Poll instead. List a monitor’s detected changes (paginated via cursor, filterable by since / until / tag), then fetch full details for any change: text diff for page monitors, added_urls / removed_urls for sitemaps, and evidence with before/after snapshots plus confidence and importance for semantic monitors.
There’s also an account-wide feed across all monitors, GET /monitors/changes (client.monitors.listAccountChanges()), and the same pair for run history: GET /monitors/{monitor_id}/runs and GET /monitors/runs.

Run, pause, and manage

Trigger an off-schedule check (queued and processed asynchronously), pause and resume, or delete:
Two behaviors worth knowing:
  • Updating target or change_detection resets the baseline. The next run re-captures it instead of reporting a spurious change. Unsupported target/detection combinations are rejected — see Pick a target for the allowed pairs.
  • Failures don’t kill monitors. A failed run flips status to failed (with last_error populated), but the monitor keeps running on schedule and flips back to active on the next success. Monitors auto-pause after repeated consecutive failures or insufficient-credit skips; resume by updating status to active.
  • A failed baseline run pauses the monitor immediately. The baseline is the first run after you create the monitor or edit its target or change_detection — if that run fails, the configuration itself is probably wrong, so Context.dev sets status to paused and populates last_error on the first failure instead of burning retries. Fix the configuration (or leave it alone if the source was transiently down) and resume with status: "active" to clear last_error and re-run the baseline.
  • Empty, blocked, error, parked, or collapsed pages don’t overwrite the baseline. If a run’s snapshot looks degraded — a bot-block interstitial, an error page, a parked domain, or a page that shrank to almost nothing — the run fails cleanly instead of poisoning the baseline with a bad snapshot and firing a spurious disappearance/recovery alert pair on the next healthy run.

Pricing

Creating, listing, updating, and reading monitors, runs, and changes is free. You pay per run, priced like the equivalent public endpoint: Monitor spend appears on the usage page under the path /v1/monitors/run, and GET /monitors/credit-usage returns a per-monitor credit and run breakdown over any time window:
cURL

Use cases

  • Competitor price tracking: a page monitor on each competitor’s pricing page, with the webhook posting diffs into Slack. Add target.instructions like “report pricing or plan availability changes, ignore counters and testimonials” to make it semantic and skip the cosmetic churn.
  • Content ops: a sitemap monitor on a competitor’s blog to catch new posts and landing pages the day they ship.
  • Positioning intelligence: an extract + semantic monitor with instructions like “track packaging, pricing, and headline feature claims”; cosmetic rewording won’t fire it.
  • Compliance watch: an extract monitor over terms or privacy pages, alerting only when obligations meaningfully change.
  • Your own site: a sitemap monitor as a tripwire for pages accidentally dropping out of your sitemap after a deploy.

Next steps

Monitors API Reference

Every endpoint, parameter, and response schema.

Extract Structured Data

The schema-driven extraction that powers extract monitors.

Best Practices

Caching, error handling, and key hygiene.

Troubleshooting

Status codes, retry patterns, and common errors.