Skip to main content
Watch a page for changes: a price, a stock status, a policy page, a competitor’s pricing table, a job board. Each check fetches the page, compares it with the last snapshot, and sends you a diff when it differs. Uses: Fetch with response_type=markdown or css_extractor, Batch scheduled jobs

How it works

  1. Fetch reads the page. Fetch with mode=auto returns either the whole page as markdown, or only the fields you name in a css_extractor. Watching fields ignores changes elsewhere on the page, such as ads or timestamps.
  2. Your code hashes and diffs. The script hashes the content and compares it with the hash stored in snapshots.json. When they differ, it builds a line-by-line diff.
  3. The alert goes out. The diff goes to a Slack incoming webhook when SLACK_WEBHOOK_URL is set, and to the console otherwise.
  4. A schedule repeats it. Run the script from cron, or let a scheduled Batch job fetch the pages and run the same diff on its results.

Ask your AI agent

With the Zenrows MCP server connected to Claude, Cursor or any MCP client, paste this prompt. Your agent picks the right Zenrows tools and settings on its own.

Watch pages for changes

List what to watch in WATCHES. An entry with a css_extractor watches those fields. An entry without one watches the whole page as markdown. Save this as watch.py and run python watch.py: the first run saves a baseline, every later run compares against it.
Python (Requests)
To send alerts to Slack, create an incoming webhook and export its URL as SLACK_WEBHOOK_URL. The same {"text": ...} payload works with Microsoft Teams workflows, Discord (as content) and most chat tools.

Run it on a schedule

With cron. Check every hour from your own server:
With a scheduled Batch job. Zenrows fetches the pages on its schedule, and your code only diffs the results. Each task carries its own zenrows_params, so one job mixes field watches and full-page watches. Run this once to create the job (pip install zenrows):
Python (SDK)
Zenrows posts a run.completed event to the webhook after each run. Call this function from your webhook handler (or from cron, after the scheduled time) to diff the run’s results against your snapshots:
Python (SDK)
Zenrows delivers each webhook event at least once, so deduplicate on the X-ZenRows-Event-Id header. To verify that deliveries come from Zenrows, enable signed webhooks, see Verify signed webhooks.

Example output

Output of watch.py: the first run, then a second run with no changes:
A later run, after setting the stored prices to 79.00and79.00 and 62.00 in snapshots.json to simulate a change. The field watch shows the changed field, the markdown watch shows the changed line:

Customize it

Troubleshooting

  • Every run reports a change: the page includes content that changes on each load, such as a timestamp, a session token or rotating ads. Switch that watch to a css_extractor with only the fields you care about.
  • The diff is empty but a change was reported: the content changed only in whitespace or line order. Normalize the content before hashing, for example " ".join(content.split()).
  • A field comes back empty: the selector no longer matches. Inspect the element in your browser and update the css_extractor.
  • Webhook events arrive twice: deliveries are at least once. Store each X-ZenRows-Event-Id you process and skip repeats.

Build a price monitor

Store price history and alert on drops.

Run a Batch job on a schedule

Every schedule option for Batch jobs.

Get notified when a Batch job finishes

Receive and verify Batch webhooks.

Turn any web page into LLM-ready markdown

More on response_type=markdown.