Uptime checksHTTP, keyword and TLS checks on your addresses, with the evidence of every failure kept.
Cron heartbeatsOne curl line at the end of a job. Silence past the grace window is the alert.
Status pagesA page your customers read, on your own domain, with the incident in plain words.
ExplanationsA written reason with the alert: what failed, what the checks saw, what to look at first.
on every plan Alerts to six channelsImportTeams
APIRead, pause, acknowledge and post updates from your own scripts.
MCP serverAsk your AI assistant what is down, then acknowledge or post an update.
WebhooksSigned JSON when an incident opens, is acknowledged or recovers.
Heartbeat guidescrontab, GitHub Actions, Railway, Node, Go, WordPress and Kubernetes.
DocsShort guides, each one task, with the lines to copy.
GuidesWhy monitors send false alarms, why cron jobs stop, and the fix.
ChangelogThe big things we shipped, newest first.
Trust and securityWhere your data lives, who processes it, how long we keep it.
Referral program soonRecommend Upglory to another team. In the works.
Contact
Docs menu Heartbeats / GitHub Actions

Monitor a scheduled GitHub Actions workflow.

One step at the end of the job. Four minutes, start to finish.

4 minute read Guide

Before you start

You need a heartbeat in Upglory with its period and grace set to match the workflow's schedule. Its page shows the ping address; keep it in a repository secret called UPGLORY_PING_URL.

Settings that match this schedule

  • Period24 hoursThe cron in the workflow's own schedule block, not the run time.
  • Grace35 minutesThe longest run you have seen, plus the late start GitHub sometimes gives a scheduled workflow.
  • Channelsemail, TelegramInherited from the workspace default. Change it on this heartbeat if it matters less than the others.

The line

Add one step at the end of the job. if: success() is the whole trick: the step is skipped when anything before it failed, so a failed run looks the same to us as a run that never started.

workflow yaml
# the last step of the job
- name: Tell Upglory the job finished
  if: success()
  run: >
    curl -fsS -m 10 --retry 3
    "${{ secrets.UPGLORY_PING_URL }}"

The URL is unique to this heartbeat and is not a secret in the security sense: anyone holding it can only say "the job ran". Keep it in repository secrets anyway, so it does not appear in a public log. A scheduled workflow on GitHub can start late under load, so give the grace window room.

Measure the run time

Make it the first step of the job. The step at the end then records how long the run took, and a slow run is not mistaken for a missed one.

- name: Tell Upglory the job started
  run: curl -fsS -m 10 "${{ secrets.UPGLORY_PING_URL }}/start"

Report a failure

if: failure() runs this step only when an earlier one failed, so you hear at once instead of when the grace window runs out.

- name: Tell Upglory the job failed
  if: failure()
  run: curl -fsS -m 10 "${{ secrets.UPGLORY_PING_URL }}/fail"

Test it

Use Send a test ping on the heartbeat's page, or add workflow_dispatch to the workflow's triggers and run it by hand from the Actions tab. Nothing alerts until the first ping arrives, so a job you have not deployed yet never raises an alarm.

What you will see if it stops

Thirty-five minutes after the workflow should have finished, the heartbeat turns down and you get the alert with the last ping time in it. Check the Actions tab first: a workflow disabled after sixty days of no repository activity is the common cause, and it looks exactly like a job that stopped.

missed nightly-build
LATE due 03:00, grace ran out 03:35
last ping yesterday 03:06, ran 6 min 40 s
Email and Telegram told at 03:35

The other guides

Start free 20 heartbeats on Free, with no card