# GitHub Actions failure alerts on your iPhone

> Push a GitHub Actions failure to your iPhone with one workflow step, one group per repository and branch, and a recovery when the branch is green again.

Source: https://honk-me.app/guides/github-actions-failure-alerts

GitHub can already tell you about workflow runs. Turn on notifications for Actions in the GitHub Mobile app, and you get a push for runs you started. If that’s all you need, you’re done.

Honk is for when you need more: failures from many repositories, including runs other people started, folded into one group per branch, in the same inbox as your servers and cron jobs, with a recovery when the branch is green again. This guide adds it with one step at the end of a job.

## Before you start

- A Honk account. Honk is invite-only for now: [request access](https://honk-me.app/request-access).
- A project for CI and an ingestion key: in the web app, open the project, then **Keys**, and create one.

## 1. Store the URL and the key as secrets

Repository secrets work for a single repository; organization secrets save you from repeating this everywhere. With the GitHub CLI:

```sh
# with the GitHub CLI, for one repository (or use --org for all of them)
gh secret set HONK_URL --body "https://honk-me.app"
gh secret set HONK_KEY        # paste the ingestion key when asked
```

## 2. Add a step that runs only on failure

Put this step last in the job you care about. `if: failure()` runs it only when an earlier step failed. It uses `jq` and `curl`, which every GitHub-hosted runner already has, so there is nothing to install:

```yaml
      - name: Tell Honk
        if: failure()
        env:
          HONK_URL: ${{ secrets.HONK_URL }}
          HONK_KEY: ${{ secrets.HONK_KEY }}
          WORKFLOW: ${{ github.workflow }}
          REPO: ${{ github.repository }}
          BRANCH: ${{ github.ref_name }}
          RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
          ATTEMPT: ${{ github.run_id }}-${{ github.run_attempt }}
        run: |
          jq -n --arg title "CI failed: $WORKFLOW on $BRANCH" --arg url "$RUN_URL" --arg key "ci/$REPO/$BRANCH" \
            '{title: $title, message: $url, url: $url, severity: "long", event_type: "problem",
              group_key: $key, source: "github-actions", category: "deployments"}' |
          curl -sS --max-time 10 --retry 3 --retry-all-errors "$HONK_URL/v1/messages" \
            -H "Authorization: Bearer $HONK_KEY" -H "Content-Type: application/json" \
            -H "Idempotency-Key: gh-$ATTEMPT" --data-binary @- || true
```

A few choices in there matter:

- **The group key is the repository and the branch**, `ci/acme/api/main`. The first failure on `main` pushes; more failures on `main` fold into the same group and become calm updates. A failure on another branch gets its own group.
- **The idempotency key is the run ID plus the attempt number.** If curl retries after a lost response, Honk returns the original event instead of a second one, but when you press **Re-run**, the new attempt is a new event.
- **`jq` builds the JSON**, so a workflow or branch name with quotes in it can’t break the request.
- **`|| true`** means a Honk outage can never turn a failed build into a different failure.

## 3. Optional: a recovery when it’s green again

To close the incident when the branch passes again, add a second step that runs on success, asks GitHub whether the previous run on this branch failed, and only then reports a recovery:

```yaml
      # needs `permissions: actions: read` when the workflow restricts the token
      - name: Tell Honk it works again
        if: success()
        env:
          GH_TOKEN: ${{ github.token }}
          HONK_URL: ${{ secrets.HONK_URL }}
          HONK_KEY: ${{ secrets.HONK_KEY }}
          WORKFLOW: ${{ github.workflow }}
          REPO: ${{ github.repository }}
          BRANCH: ${{ github.ref_name }}
          ATTEMPT: ${{ github.run_id }}-${{ github.run_attempt }}
        run: |
          previous=$(gh run list --repo "$REPO" --workflow "$WORKFLOW" --branch "$BRANCH" \
            --limit 2 --json conclusion --jq '.[1].conclusion')
          [ "$previous" = "failure" ] || exit 0
          jq -n --arg title "CI green again: $WORKFLOW on $BRANCH" --arg key "ci/$REPO/$BRANCH" \
            '{title: $title, message: "The last run passed.", severity: "beep", event_type: "recovery",
              group_key: $key, source: "github-actions", category: "deployments"}' |
          curl -sS --max-time 10 --retry 3 --retry-all-errors "$HONK_URL/v1/messages" \
            -H "Authorization: Bearer $HONK_KEY" -H "Content-Type: application/json" \
            -H "Idempotency-Key: gh-$ATTEMPT-ok" --data-binary @- || true
```

Without this step nothing breaks: an episode with no new events becomes inactive after 24 hours, and the next failure opens a new one and pushes again.

## The same with the honk-me CLI

If you prefer the CLI, which handles retries with one idempotency key and a total deadline for you, install it in steps that run only on failure and call `problem`. Go is preinstalled on GitHub-hosted Linux runners:

```yaml
      - name: Install honk-me
        if: failure()
        run: |
          go install github.com/honk-me/honk-go/cmd/honk-me@latest
          echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"

      - name: Notify
        if: failure()
        env:
          HONK_URL: ${{ secrets.HONK_URL }}
          HONK_KEY: ${{ secrets.HONK_KEY }}
        run: |
          honk-me problem --group-key "ci/${{ github.repository }}/${{ github.ref_name }}" \
            --title "CI failed: ${{ github.workflow }}" --message "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
            --source github-actions --category deployments \
            --idempotency-key "gh-${{ github.run_id }}-${{ github.run_attempt }}" || true
```

## What you get

The first failure on `main` arrives as a Long honk, with a link to the run one tap away in the inbox. Repeats on the same branch update one group instead of buzzing again, and quiet hours hold CI failures overnight unless you send them as urgent. The [deploy guide](https://honk-me.app/guides/deploy-notifications) also covers telling Honk about successful deploys.
