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