Skip to main content

Using GitHub Actions to get notified when an API response (or web page) changes

5 min read

Summary: Rather than smashing refresh on an endpoint, let GitHub Actions call it on a schedule, using cURL to fetch the data, jq to parse the response, and Actions’ native caching to maintain state between runs. Save the workflow in .github/workflows/, swap in your URL, and get a text message (or any other notification) when the response changes.

Table of contents

Given all the uncertainty in the global supply chain these days, I was recently in the dark as to when an eagerly awaited purchase would arrive. Luckily the manufacturer had a hidden API you could call that indicated where in the supply chain the product was as it made its journey around the globe. Better still, as it got closer to delivery, the response also included its estimated delivery date.

Rather than smashing refresh on the endpoint compulsively, I realized I could use GitHub Actions to regularly call the API on my behalf and report back with any changes. These types of easy-on-the-surface projects all too often harbor the risk of overengineering, so I purposely kept things simple, using cURL to fetch the data, jq to parse the response, and GitHub Actions’ native caching library to maintain state between runs. It took only a handful of lines of YAML and no real code, and it worked better than I expected.1

If you need to track when an API response or web page changes (delivery related or otherwise), you’re welcome to follow my approach. I used Twilio’s SMS action (along with a free trial account) to send a text message when the response changed, but there are a number of existing community Actions available that could be used for notifications, from GitHub Issues to app-based mobile push to Slack.

Setup

To set up the notify-on-changes GitHub Action to track changes to your own API or web page response, just follow these steps:

  1. Save the below snippet as a YAML file in the .github/workflows/ folder (for example, .github/workflows/check.yml) of a public or private GitHub repository.
  2. Swap out the <URL YOU WANT TO CHECK HERE> placeholder for the actual API endpoint or web page URL you want to check.2
  3. To parse out the JSON response so that you can include a specific field or fields from the response in the notification you send yourself, modify the jq query. Otherwise, you can remove the “Parse data” step entirely.
  4. If using Twilio to receive notifications via text message, follow the setup instructions, saving the keys and phone numbers as repository secrets and customizing the message for your use case. Otherwise, swap out the “Notify if data has changed” step to use your own notification mechanism.3
  5. Commit and effortlessly receive notifications any time the response changes.

Example workflow

Here’s the annotated YAML for the workflow I used, in its entirety:

on:
schedule:
# Run every hour, on the hour. This can be customized to checking as frequently as every 5 minutes.
- cron: '0 * * * *'
name: Check for changes
jobs:
check:
runs-on: ubuntu-latest
steps:
# Use cURL to fetch the given URL, saving the response to `data.json`
- name: Fetch data
run: curl "<URL YOU WANT TO CHECK HERE>" -o data.json
# Optionally, use `jq` to pull one or more fields from the JSON to include in the SMS message
- name: Parse data
id: parse_data
run: echo "someField=$(jq -r '.someField' data.json)" >> "$GITHUB_OUTPUT"
# Compare the response to the previous run, using a hash of the response as the cache key
- name: Fetch Cache
id: cache
uses: actions/cache@v4
with:
path: data.json
key: ${{ hashFiles('data.json') }}
# If there was not a cache hit (meaning the response changed), notify me via text message
# See https://github.com/twilio-labs/actions-sms for setup instructions
# You could use a different notification action here, so long as you include the `if` condition below
- name: Notify if data has changed
uses: twilio-labs/actions-sms@v1
if: steps.cache.outputs.cache-hit != 'true'
env:
TWILIO_ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }}
TWILIO_API_KEY: ${{ secrets.TWILIO_API_KEY }}
TWILIO_API_SECRET: ${{ secrets.TWILIO_API_SECRET }}
with:
fromPhoneNumber: ${{ secrets.from_phone }}
toPhoneNumber: ${{ secrets.to_phone }}
message: "There's been a change! someField is now ${{ steps.parse_data.outputs.someField }}."

Stop hitting refresh

My obsessive package tracking is now yours to reuse, whatever you’re waiting on. If you adapt the workflow for something creative, I’d love to hear about it.

Footnotes

  1. In fact, the purchase arrived ahead of schedule, but I don’t think I can give the workflow credit for that. ↩︎

  2. It can be an authenticated endpoint, too. Just store your API key as a repository secret to keep it out of your codebase. ↩︎

  3. If you use a different notification mechanism, be sure to include the if: steps.cache.outputs.cache-hit != 'true' conditional, to ensure that the notification is only sent if the response has changed. ↩︎

Keep reading

Ben Balter

I'm Ben Balter, and I write here about developer platforms, product and engineering leadership, open source, and showing your work. I spent over a decade building developer platforms at GitHub. For five years I was a product manager for trust and safety, shipping 500+ features and the API endpoints behind them to 50M+ developers. I also led a bottom-up rewrite of GitHub Pages and wrote the open source library behind GitHub's license detection, and my open source projects have hundreds of millions of downloads. I wrote Open and Async, the playbook for remote and distributed teams, and shipped a Model Context Protocol (MCP) server alongside it so agents can query it directly. More about the author

Follow along: Bluesky LinkedIn

Originally published December 15, 2021 View revision history

This page is open source Help improve this article on GitHub

Keyboard shortcuts

Search

  • / or ⌘ K Open search
  • ↓ or j ↑ or k Move through results
  • Enter Open the selected result
  • Esc Close search

Go to

  • g then h Home
  • g then p All posts

This page

  • y Copy link to this page
  • ? Show this list