A scheduled workflow can fail when a vendor pricing page, docs page, or changelog changes its text. The job below reads the latest event from a SignalWatch monitor and exits 1 if that event is a content change from the last six hours.
This is for public, server-rendered pages. It does not render JavaScript, log in, or take a screenshot. If the price only exists after a client-side render, the monitor will not see it.
The workflow
Save this as .github/workflows/upstream-drift.yml. It uses GNU date, which ubuntu-latest provides.
name: upstream-drift on: schedule: - cron: "0 */6 * * *" workflow_dispatch: jobs: check: runs-on: ubuntu-latest steps: - name: Fail if the vendor page changed in the last 6h env: KEY: ${{ secrets.SIGNALWATCH_KEY }} CHECK_ID: "123" run: | latest=$(curl -fsS "https://signalwatch.litework.me/api/v1/checks/$CHECK_ID/events?limit=1" -H "X-API-Key: $KEY") event=$(echo "$latest" | jq -r '.[0].event // "none"') when=$(echo "$latest" | jq -r '.[0].created_at // "1970-01-01T00:00:00Z"') age=$(( $(date +%s) - $(date -d "$when" +%s) )) if [ "$event" = "changed" ] && [ "$age" -lt 21600 ]; then echo "::error::Upstream page changed" echo "$latest" | jq -r '.[0].diff' exit 1 fi echo "no recent change ($event, ${age}s ago)" Add the API key as a repository secret named SIGNALWATCH_KEY. Replace 123 with the monitor id from the dashboard.
The events endpoint returns the newest row first. On that API a content change is event: "changed". Webhook deliveries for the same moment use content.changed. diff is a unified text diff. change_ratio is changed characters divided by the longer of the two texts.
Create the monitor
Free covers 3 monitors at a 15 minute interval, no card: https://signalwatch.litework.me/
Two settings matter more than the schedule:
- A CSS selector, so you hash the price table or the docs section instead of the whole document.
- An ignore regex, so a line like "updated 3 minutes ago" does not fail the build.
There is a public monitor on the Hacker News front page if you want to read real diffs before creating an account: https://signalwatch.litework.me/live.html
Curl, Python, and signature checks, including this workflow, are on the examples page: https://signalwatch.litework.me/examples.html
What a failure looks like
The Actions log prints the diff and the job goes red:
--- before +++ after @@ -3 +3 @@ -Starter $10/mo +Starter $14/mo Downtime is a different event (down, then up when the fetch recovers). Those do not fail this job. Extend the if if a failed fetch should fail CI as well.
Limits
Public http(s) URLs only. Fetches are capped at 2 MB and follow up to 3 redirects. JavaScript is not executed.
Email, Slack, Discord, and HMAC-signed JSON are the push path. This workflow is the pull path, for a repo that already lives in Actions and wants upstream drift to turn the badge red.
The same idea as a push into n8n: https://dev.to/signalwatch/run-an-n8n-workflow-when-a-pages-text-changes-38m0