Skip to content
LastPing
GUIDE · GITHUB ACTIONS · FREE

Monitor GitHub Actions, and get told why a run failed

Point one signed workflow_run webhook from your repository at LastPing: zero changes to your workflow YAML. Every run reports in; a run that fails, hangs, or never starts opens an incident, alerts you where you work, and deep-links to the run. Free for individuals, no monitor cap.

Your assistant can do this for you

Monitor my GitHub Actions workflows with LastPing

On this page
  1. Scheduled workflows fail silently. By design.
  2. Setup: one webhook, about two minutes
  3. What this catches
  4. Questions people ask

Scheduled workflows fail silently. By design.

If you run a nightly build, a scraper, a DB backup, or a cert renewal on a GitHub Actions schedule, three failure modes are waiting for you, and GitHub tells you about none of them reliably.

Failure mode 01

The 60-day silent disable

GitHub automatically disables schedule-triggered workflows in public repositories after 60 days without activity. No error, and no email when it happens: your nightly backup just stops existing.

Failure mode 02

Email to the wrong person

A failed scheduled run only notifies the user who last touched the workflow's cron: often a teammate who left, or you, in an inbox filter you stopped reading months ago.

Failure mode 03

The hung run

A run that starts and never finishes (stuck runner, hung step, infinite retry) notifies nobody. It isn't a failure yet, so no failure email ever comes.

Adding a curl ping step to each workflow (the classic heartbeat approach) fixes none of the hard cases: the step never executes when the runner hangs or when the schedule was disabled. The fix is to listen to GitHub's own run signal instead, and to expect it on a schedule, so absence is an alert too.

Setup: one webhook, about two minutes

No YAML changes, no agent, no GitHub App permissions: a plain repository webhook, HMAC-verified on every delivery.

Create a CI check in LastPing

In the console, create a monitor, choose CI pipeline, and pick GitHub Actions. Give it the same schedule as your workflow (e.g. daily with a grace window) so a run that never starts is caught too. Copy the webhook URL and the one-time secret shown on screen.

https://ping.lastping.dev/ci/github/<check-id>

Register the webhook in your repository

On GitHub: Settings → Webhooks → Add webhook.

  • Payload URL: the webhook URL from step 1
  • Content type: application/json
  • Secret: the one-time secret from step 1
  • Events: "Let me select individual events" → tick Workflow runs and Workflow jobs (untick the pre-selected Pushes)
  • Why both? workflow_run tells LastPing the run failed; only workflow_job carries per-step conclusions, so it is the sole source of the failing step name in your alert. Skip it and alerts read "failed on main" instead of "failed at Run make test on main". Job events never count as extra runs.

Done: every run now reports in

LastPing verifies each delivery's HMAC signature against your secret, then classifies the run: success, failure, started. Branch and workflow filters let you count only the runs you care about (say, main and the workflow named nightly-backup). A filter only counts exact matches, so a moved default branch can leave a branch filter matching nothing. When the filters keep ignoring finished runs and none has matched since they were set, the monitor's Overview says so, counts the ignored runs, names the last one and links to the filters; if every ignored run belonged to another workflow, it says the monitor is waiting for the first run of yours and that the workflow name has to match exactly. It also speaks up when the last match is more than 72 hours old and runs of the monitor's own workflow have been ignored on other branches since; runs of other workflows, which a repository webhook also sends, are the filter doing its job and do not raise it. If your workflow has not run for 72 hours while a workflow name that first appeared after its last match has run at least twice, the Overview flags a likely rename and names the new workflow. A rename is flagged only after a monitor's first 7 days, and one made before this check existed is not flagged after the fact; a scheduled monitor still alerts when its runs stop arriving. Alerts go to email by default (your verified address is attached automatically) and to Slack, Discord, Telegram, ntfy, Pushover, Microsoft Teams, Google Chat or a signed webhook if you add them.

Optional: attach the failure reason to the incident

One if: failure() step POSTs a log excerpt (up to 64 KB, plain text) to the check's detail endpoint. It's stored on the open incident and shown in the console, so the alert doesn't just say "it broke," it shows why. The body is never logged server-side.

LASTPING_CI_SECRET is the same CI secret this monitor's webhook signs with: open the monitor in the console, go to its CI settings and reveal the secret (the reveal is password-gated), then save it as a repository secret alongside LASTPING_CHECK_ID. Sending it also lifts the throttle: without the token, detail posts are limited to 60 per 15 minutes per monitor; with it, there is no limit.

The trailing || true is not decoration: this step only runs on a job that has already failed, and a hiccup reporting the failure (a rate limit, a deleted monitor) must never be what turns the job red a second time.

# optional last step of any job in the workflow
- name: Report failure detail to LastPing
  if: failure()
  env:
    LASTPING_CI_SECRET: ${{ secrets.LASTPING_CI_SECRET }}
    LASTPING_CHECK_ID: ${{ secrets.LASTPING_CHECK_ID }}
    DETAIL: ${{ github.workflow }} / ${{ github.job }} failed on ${{ github.ref_name }} — run ${{ github.run_id }}
  run: |
    curl -fsS -X POST -H "Content-Type: text/plain" \
      -H "X-LastPing-Token: $LASTPING_CI_SECRET" \
      --data "$DETAIL" \
      "https://ping.lastping.dev/ci/$LASTPING_CHECK_ID/detail" || true

What this catches

The same durable detection engine as LastPing's cron monitoring: deadlines live in the database, so a restart never misses a due check.

  • Failed runs: incident opens with a deep link to the exact run, plus the failure detail if you added the optional step.
  • Hung runs: the run started but never completed; the completion signal doesn't arrive in the window, and that silence opens an incident.
  • Runs that never start: including scheduled workflows GitHub disabled after 60 days of inactivity in a public repo. No run signal in the expected window → incident.
  • Recovery: the next successful run closes the incident and sends a recovery notice automatically. No manual reset.
  • Flap protection: a run that fails and immediately recovers within the damping window doesn't page you.

Prefer the classic style? You can still end any workflow job with curl -fsS https://ping.lastping.dev/<id> as a plain heartbeat: it works, and it's the right tool for scripts inside a run. Just know its limits: it can't see hung runs or disabled schedules. The webhook can. GitLab CI and Jenkins are supported the same way, or see the copy-paste guides for cron, Kubernetes, systemd, and more.

Questions people ask

Front-loaded answers: the most important fact first.

  • How do I get alerted when a GitHub Actions workflow fails?

    Point one signed webhook from your repository at LastPing (Settings → Webhooks → Add webhook), ticking both the Workflow runs (workflow_run) and Workflow jobs events, with zero changes to your workflow YAML. Every run reports in; a failed, hung, or never-started run opens an incident and alerts you by email, Slack, Discord, Telegram, ntfy, Pushover, Microsoft Teams, Google Chat or webhook, with a deep link to the run and the name of the step that failed. Free for individuals, no monitor cap.

  • Why did my scheduled GitHub Action stop running?

    In a public repository, GitHub automatically disables scheduled workflows after 60 days without activity, and nothing notifies anyone when it happens. Failed scheduled runs also only email the user who last touched the workflow's cron schedule, and a run that hangs notifies nobody. A dead-man's-switch monitor like LastPing catches all three cases: it expects a run signal on your schedule and opens an incident when the signal doesn't arrive.

  • Do I need to change my workflow YAML to monitor GitHub Actions with LastPing?

    No. Monitoring uses GitHub's own workflow_run webhook, registered once per repository in Settings → Webhooks. Optionally, you can add a one-line if: failure() step to a workflow to attach the failure log excerpt directly to the LastPing incident, but the monitoring itself needs zero YAML changes.

  • Does GitHub Actions monitoring work for private repositories?

    Yes. GitHub delivers repository webhooks for private repositories exactly as for public ones. LastPing verifies each delivery against your webhook secret (HMAC signature) before processing, and never needs read access to your code.

  • Is GitHub Actions monitoring free in LastPing?

    Yes. LastPing is free for individuals, and CI/CD monitoring is a first-class feature with no monitor cap. GitLab CI and Jenkins are supported the same way. See how LastPing compares to Healthchecks.io and Cronitor.

FREE FOR INDIVIDUALS · FULLY HOSTED

Your next silent failure is already scheduled.

One webhook now beats a post-mortem later. First alert wired up in about two minutes, and LastPing monitors itself the same way.