Tutorial: Scheduled monitoring with cron, watch, and notifications
Set up Refract to re-observe Wikipedia pages on a schedule, detect when claims change, and notify you via Slack, email, or webhook. Catch citation removal, template disputes, and section reorganization as they happen — not when someone notices.
Two monitoring modes
Section titled “Two monitoring modes”| Mode | How it works | Use when |
|---|---|---|
refract cron |
One-shot re-observation for cron scheduling | Batch monitoring of many pages on a fixed schedule |
refract watch |
Polls one page and prints its new revisions until stopped | Following a specific page as it changes |
These modes alert you to changes; they do not record what anyone inspected. For that, use
refract review, and see
how all the monitoring commands compare.
Step 1: Create your pages file
Section titled “Step 1: Create your pages file”List the pages you want to monitor, one per line:
cat > watch-pages.txt << EOFCOVID-19SARS-CoV-2COVID-19_pandemicCOVID-19_vaccinemRNA_vaccineEOFPages can be any valid MediaWiki page title. Use underscores for spaces.
Step 2: Run a one-shot re-observation
Section titled “Step 2: Run a one-shot re-observation”refract cron watch-pages.txt --interval 24 --cache-dir ~/.refract-watchThis re-observes every page in the file over the last 24 hours and prints, per page,
how many events are new since the previous run. The first run for a page records a
baseline and reports none. --cache-dir is where cron keeps each page's previous
observation; without it, ~/.wikihistory. The cron reference describes
the comparison, the output and the exit code.
Step 3: Schedule it
Section titled “Step 3: Schedule it”Add to your crontab, with the interval matching the schedule:
# Every 6 hours0 */6 * * * refract cron /path/to/watch-pages.txt --interval 6 --cache-dir /path/to/stateWith --interval the window slides between runs. The
cron reference describes how events are compared across
windows.
On GitHub Actions the runner starts empty, so the state directory has to be carried between runs — cached or committed — or every run is a first run and reports nothing. The cron reference has a complete workflow that does this.
Refract spaces its requests to the MediaWiki API (100 ms apart by default) and retries
a 429 or 503 after the server's Retry-After.
Step 4: Set up notifications
Section titled “Step 4: Set up notifications”Notifications go out only when a page has new or resolved events.
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..."
refract cron watch-pages.txt --interval 24 --notify-slackThe message lists each changed page with its counts:
Refract observation report2 page(s) changed since last observation.
COVID-193 new event(s), 0 resolvedChanges detected
mRNA_vaccine5 new event(s), 1 resolvedChanges detectedexport SMTP_TO="researcher@example.com"
refract cron watch-pages.txt --interval 24 --notify-emailMail goes through the local sendmail (/usr/sbin/sendmail, or the path in
SMTP_SENDMAIL). There is no SMTP host, user or password setting.
Webhook
Section titled “Webhook”refract cron watch-pages.txt --interval 24 --notify-webhook https://your-server.com/hooks/refractRefract POSTs a JSON summary — per page, the new and resolved counts. The payload is in the cron reference.
Step 5: Live polling with watch
Section titled “Step 5: Live polling with watch”For one page, as it changes:
refract watch "COVID-19" --interval 60000Polls every 60 seconds (--interval is in milliseconds) and prints each new revision
with the events it produced, one - <eventType> <detail> line per event.
--section "Vaccine safety" limits section events to that section. The output is text
for people; a pipe can still pick lines out of it:
refract watch "COVID-19" | while read -r line; do case "$line" in *citation_removed*) echo "Citation removed from COVID-19: $line" | mail -s "Refract alert" researcher@example.com ;; esacdonewatch polls until stopped.
Step 6: Get the events themselves
Section titled “Step 6: Get the events themselves”cron reports counts. For the events, run analyze over the same window with
--json, which prints one JSON event per line:
SINCE=$(date -u -d '25 hours ago' +%Y-%m-%dT%H:%M:%SZ) # GNU date (Linux)SINCE=$(date -u -v-25H +%Y-%m-%dT%H:%M:%SZ) # BSD date (macOS)
# Citation removals — often the first sign a claim is about to changerefract analyze "COVID-19" --since "$SINCE" --json | jq -c 'select(.eventType == "citation_removed")'
# Template changes — dispute, neutrality and citation-needed tagsrefract analyze "COVID-19" --since "$SINCE" --json | jq -c 'select(.eventType | startswith("template_"))'The window opens an hour before the day it covers because the first revision inside a
--since window is not diffed against the one before it.
Step 7: Integrate with your own alerts
Section titled “Step 7: Integrate with your own alerts”while read -r page; do refract analyze "$page" --since "$SINCE" --json | while read -r event; do if [ "$(echo "$event" | jq -r '.eventType')" = "citation_removed" ]; then echo "ALERT: citation removed from $page / $(echo "$event" | jq -r '.section')" # Trigger your alerting pipeline fi donedone < watch-pages.txtNext steps
Section titled “Next steps”- CLI cron reference — all flags and environment variables
- Citation churn tutorial — interpreting citation patterns
- Dispute timeline tutorial — detecting edit wars
- Downstream integration — production patterns for consuming events