Page Change Watcher API
Watch a web page or one part of it (CSS selector) for content changes and get an e-mail or webhook with a unified diff of what changed.
POST /v1/page-watch with a url creates a watcher: the page is fetched at once to take a baseline, then every interval_minutes. Choose what is compared: an optional CSS selector (all matches), mode text (visible text with line breaks, scripts and styles removed), html (the markup, one tag per line) or regex (only what a pattern extracts, e.g. prices). Remove noise before comparing with ignore (up to 20 regular expressions) and ignore_presets (dates, times, numbers, including Vietnamese forms such as “ngày 11 tháng 11” and “5 phút trước”). The normalised content (up to 200 KB) is stored compressed with its SHA-256.
When the hash changes, a change event with a unified diff (truncated to 4 KB; the last 20 events are kept) is stored and sent to your webhook_url ({"event": "page.changed", "watcher", "added", "removed", "diff", "hash", "previous_hash"}) and to the verified e-mail of your account (at most one e-mail per watcher per hour, with daily caps). Three failed checks in a row raise one page.error alert. Sites answering 429 / 503 are left alone for their Retry-After (or a doubled interval); robots.txt is checked on creation and weekly, and our bot identifies itself as APIBoxBot.
GET /v1/page-watch lists your watchers, /{id} shows one with its events (include_snapshot=true adds the stored content), PATCH updates it (a new URL or rule starts a new baseline), DELETE removes it, /{id}/events returns the history and POST /{id}/check runs a test without changing anything. dry_run=true previews the normalised content without an account. Plans: Free 3 watchers every 60+ minutes, Starter 20 every 30+, Pro 100 every 15+ minutes.
Parameters
| Name | In | Type | Required | Default | |
|---|---|---|---|---|---|
url | body | string | yes | Public page to watch (required when creating). | |
name | body | string | no | Display name (max 100 characters). | |
selector | body | string | no | CSS selector of the watched part (all matches); empty = whole page. | |
mode | body | string | no | text | text, html or regex. |
pattern | body | string | no | mode regex: what to extract (group 1 if present), /…/i syntax allowed, max 200 characters. | |
ignore | body | array | no | Regular expressions removed before comparing (array or one per line, max 20). | |
ignore_presets | body | string | no | Comma list of dates, times, numbers. | |
interval_minutes | body | number | no | Check interval: from the plan minimum (60 Free, 30 Starter, 15 Pro) to 10080. Default: max(plan minimum, 60). | |
alert_email | body | boolean | no | true | E-mail the verified account address on changes. |
webhook_url | body | string | no | URL receiving a JSON POST (page.changed / page.error); empty to remove. | |
paused | body | boolean | no | false | Pause or resume checks. |
dry_run | body | boolean | no | false | Only fetch and return the normalised content (no account needed, nothing saved). |
id | path | string | no | /v1/page-watch/{id} (GET, PATCH, POST, DELETE), /{id}/events, /{id}/check (POST: test run). | |
include_snapshot | query | boolean | no | false | GET /{id}: also return the stored content. |
Example
curl -X POST "https://apibox.io.vn/v1/page-watch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.edu.vn/tuyen-sinh","name":"Tuyển sinh","selector":".news","ignore_presets":"dates","interval_minutes":60,"webhook_url":"https://example.com/hooks/page"}'const res = await fetch('https://apibox.io.vn/v1/page-watch', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "https://example.edu.vn/tuyen-sinh",
"name": "Tuyển sinh",
"selector": ".news",
"ignore_presets": "dates",
"interval_minutes": 60,
"webhook_url": "https://example.com/hooks/page"
}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://apibox.io.vn/v1/page-watch",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"url": "https://example.edu.vn/tuyen-sinh", "name": "Tuyển sinh", "selector": ".news", "ignore_presets": "dates", "interval_minutes": 60, "webhook_url": "https://example.com/hooks/page"},
timeout=30,
)
print(res.json())<?php
$ch = curl_init('https://apibox.io.vn/v1/page-watch');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => '{"url":"https://example.edu.vn/tuyen-sinh","name":"Tuyển sinh","selector":".news","ignore_presets":"dates","interval_minutes":60,"webhook_url":"https://example.com/hooks/page"}',
]);
$response = curl_exec($ch);
print_r(json_decode($response, true));Response
{
"id": "pw_ubts7ip9hp6nsep1qj1d",
"name": "Tuyển sinh",
"url": "https://example.edu.vn/tuyen-sinh",
"selector": ".news",
"mode": "text",
"pattern": null,
"ignore": [],
"ignore_presets": [
"dates"
],
"interval_minutes": 60,
"alert_email": true,
"webhook_url": "https://example.com/hooks/page",
"paused": false,
"status": "ok",
"last_check": {
"at": "2026-11-11T03:20:00.000Z",
"error": null
},
"last_change_at": null,
"changes_total": 0,
"checks_total": 1,
"snapshot": {
"sha256": "1d6fb694b0d75af3154ba70809eeb475aa4c1ff4a50a170581797e7028520d3d",
"bytes": 92
},
"next_check_at": "2026-11-11T04:20:00.000Z",
"created_at": "2026-11-11T03:20:00.000Z",
"first_check": {
"status_code": 200,
"selector_matches": 1,
"lines": 3,
"truncated": false,
"preview": "Thông báo tuyển sinh\nĐề án tuyển sinh năm 2027\nLịch thi đánh giá năng lực"
}
}
Use cases
- Get notified when a school or ministry posts a new announcement
- Track tender, recruitment or regulation pages without checking them by hand
- Watch a partner’s terms of service or pricing page for edits
- Send page changes to Slack, Telegram or your own system by webhook
FAQ
How do I avoid alerts for counters and dates?
Use a CSS selector for the part you care about, add ignore_presets=dates,times,numbers or your own ignore patterns, and check the result with dry_run=true first.
Can it watch pages behind a login?
No. Only public pages are fetched, without cookies, and URLs disallowed for our bot by robots.txt are refused.
Do scheduled checks use my quota?
No. Creating, updating, test runs and previews count one request each; GET reads are free.
Related APIs
Webhook Tester
Create a unique URL that captures every HTTP request sent to it – method, headers, query and body – then inspect them in the browser or via API.
👤Vietnamese Fake Data
Realistic Vietnamese test data: names, addresses on the 2025 map, mobile numbers by network, CCCD and tax codes with a valid structure, companies, bank accounts.
{?}JSON Schema Mock Data
Generate realistic sample JSON from a JSON Schema (types, formats, enums, patterns, ranges, $ref, oneOf / allOf), validated against the schema.