Loading...
Loading...
Detect what changed between two page snapshots with fastCRW — stateless diff as a REST primitive. Use when you need to track content changes, monitor a page for updates, or build a cron-based alert system: "has this page changed?", "alert me when pricing changes", "diff this week's scrape against last week's". Step 7 of the crw workflow ladder.
npx skill4agent add us/crw crw-watch1. Scrape now → store snapshot (markdown / json)
2. Scrape later → call /v1/change-tracking/diff with current + previous
3. On status=changed → alert / act
4. Repeat on a cron| Mode | Wire string | What it produces |
|---|---|---|
| Git-style text diff | | Unified-diff text + parse-diff AST in |
| Per-field JSON diff | | Path-keyed map |
modes["gitDiff"]"modes": ["gitDiff", "json"]curl -X POST "$CRW_API_URL/v1/change-tracking/diff" \
-H "Authorization: Bearer $CRW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"current": {
"markdown": "# Pricing\nPro plan: $49/mo"
},
"previous": {
"markdown": "# Pricing\nPro plan: $39/mo",
"contentHash": "<hash from prior result>"
},
"modes": ["gitDiff"]
}'{
"success": true,
"data": {
"status": "changed",
"firstObservation": false,
"contentHash": "<new hash>",
"snapshot": { "markdown": "...", "contentHash": "..." },
"diff": {
"text": "@@ -1,2 +1,2 @@\n # Pricing\n-Pro plan: $39/mo\n+Pro plan: $49/mo",
"json": { "files": [...] }
}
}
}batchcurl -X POST "$CRW_API_URL/v1/change-tracking/diff" \
-H "Authorization: Bearer $CRW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"batch": [
{ "url": "https://example.com/pricing", "current": {"markdown": "..."}, "previous": {"markdown": "..."} },
{ "url": "https://example.com/about", "current": {"markdown": "..."} }
],
"modes": ["gitDiff"]
}'modesschemapromptcontentTypechangeTracking/v1/scrapecurl -X POST "$CRW_API_URL/v1/scrape" \
-H "Authorization: Bearer $CRW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/pricing",
"formats": ["markdown", "changeTracking"],
"changeTracking": {
"modes": ["gitDiff"],
"previous": { "markdown": "...", "contentHash": "..." }
}
}'{ current, previous?, modes, schema?, prompt?, contentType?, tag?, goal?, judgeEnabled? }{ batch: [...items], modes, schema?, ... }{ url?, current, previous?, modes?, schema?, ... }| Field | Type | Notes |
|---|---|---|
| string | Current page content (gitDiff / mixed) |
| object | Current extracted JSON (json / mixed) |
| string | Prior snapshot for gitDiff |
| string | Persist from prior result's |
| string[] | |
| JSON Schema | Required for |
| string | Natural-language extraction prompt (alternative to |
| string | If binary/non-text, triggers byte-hash comparison only |
| string | Opaque caller ID echoed back on the result |
| string | Natural-language filter for meaningful changes (AI judge, M2) |
| bool | Enable AI judgment (M2 feature; accepted but not yet applied) |
goalgoal"Alert when the listed price changes; ignore copy rewrites and nav updates""detect important changes""Only flag changes to the Features table, not the hero section"{meaningful, confidence, reason, meaningfulChanges[]}judgment#!/usr/bin/env bash
# cron-check.sh — run every hour via cron or a scheduler
SNAPSHOT_FILE=".crw/snapshot.json"
CURRENT=$(crw scrape "https://example.com/pricing" --format markdown)
if [ -f "$SNAPSHOT_FILE" ]; then
PREV_MARKDOWN=$(jq -r '.markdown' "$SNAPSHOT_FILE")
PREV_HASH=$(jq -r '.contentHash' "$SNAPSHOT_FILE")
RESULT=$(curl -s -X POST "$CRW_API_URL/v1/change-tracking/diff" \
-H "Authorization: Bearer $CRW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"current\":{\"markdown\":$(jq -Rsc . <<<"$CURRENT")},\"previous\":{\"markdown\":$(jq -Rsc . <<<"$PREV_MARKDOWN"),\"contentHash\":\"$PREV_HASH\"},\"modes\":[\"gitDiff\"]}")
STATUS=$(echo "$RESULT" | jq -r '.data.status')
if [ "$STATUS" = "changed" ]; then
echo "CHANGED: $(echo "$RESULT" | jq -r '.data.diff.text')"
# → send alert, write to DB, trigger webhook, etc.
fi
echo "$RESULT" | jq '.data.snapshot' > "$SNAPSHOT_FILE"
else
# First observation — store the snapshot
curl -s -X POST "$CRW_API_URL/v1/change-tracking/diff" \
-H "Authorization: Bearer $CRW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"current\":{\"markdown\":$(jq -Rsc . <<<"$CURRENT")},\"modes\":[\"gitDiff\"]}" \
| jq '.data.snapshot' > "$SNAPSHOT_FILE"
fisnapshotprevioussnapshotcontentHashfirstObservation: truepreviousstatus: "changed"snapshotjsoncurrent.jsongitDiffmodesschemaprevious