Contents
GitHub Actions integration

GitHub Actions push notifications

PushPiper pings your phone when a GitHub Actions workflow fails or a deploy lands, free for 10,000 messages a month. It's one run: curl step with your keys in repository secrets, no third-party action needed.

Before you start

  1. Sign in at pushpiper.com/app (free, no credit card) and create an app called GitHub. Its API token is your APP_TOKEN.
  2. Copy your user key from the dashboard. That's your USER_KEY.
  3. In your repository, go to Settings > Secrets and variables > Actions and add two repository secrets: PUSHPIPER_TOKEN and PUSHPIPER_USER.

Get a push when a build fails

Workflow
name: CI

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: npm ci
      - run: npm test

      - name: Ping PushPiper on failure
        if: failure()
        env:
          PUSHPIPER_TOKEN: ${{ secrets.PUSHPIPER_TOKEN }}
          PUSHPIPER_USER: ${{ secrets.PUSHPIPER_USER }}
        run: |
          curl -sS --fail-with-body https://api.pushpiper.com/1/messages.json \
            --data-urlencode "token=$PUSHPIPER_TOKEN" \
            --data-urlencode "user=$PUSHPIPER_USER" \
            --data-urlencode "title=$GITHUB_REPOSITORY: $GITHUB_WORKFLOW failed" \
            --data-urlencode "message=Branch $GITHUB_REF_NAME, commit ${GITHUB_SHA::7}" \
            --data-urlencode "priority=1" \
            --data-urlencode "url=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
            --data-urlencode "url_title=Open the run"

if: failure() runs the step only when an earlier step failed. The notification goes out at priority 1, so it gets through quiet hours, and its link opens the failed run.

Keys and run details reach curl as environment variables instead of being pasted into the script, so a branch name with quotes can't break the command, and --data-urlencode takes care of the encoding.

Report every deploy

Workflow
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: ./deploy.sh

      - name: Ping PushPiper
        if: always()
        env:
          PUSHPIPER_TOKEN: ${{ secrets.PUSHPIPER_TOKEN }}
          PUSHPIPER_USER: ${{ secrets.PUSHPIPER_USER }}
          JOB_STATUS: ${{ job.status }}
        run: |
          priority=0
          if [ "$JOB_STATUS" != "success" ]; then priority=1; fi

          curl -sS --fail-with-body https://api.pushpiper.com/1/messages.json \
            --data-urlencode "token=$PUSHPIPER_TOKEN" \
            --data-urlencode "user=$PUSHPIPER_USER" \
            --data-urlencode "title=$GITHUB_WORKFLOW: $JOB_STATUS" \
            --data-urlencode "message=$GITHUB_REPOSITORY on $GITHUB_REF_NAME" \
            --data-urlencode "priority=$priority" \
            --data-urlencode "url=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
            --data-urlencode "url_title=Open the run"

if: always() runs the step whether the job passed or not, and job.status says which. Failures and cancellations get priority 1, successes a normal ping.

Handy values for your message

VariableHolds
GITHUB_REPOSITORYOwner and repository, like acme/web
GITHUB_WORKFLOWThe workflow's name
GITHUB_REF_NAMEThe branch or tag that triggered the run
GITHUB_SHAThe full commit SHA. ${GITHUB_SHA::7} shortens it
GITHUB_ACTORWho started the run
GITHUB_SERVER_URL, GITHUB_RUN_IDWith the repository, the link to the run

Every runner sets these. The full list is in GitHub's variables reference.

Limits and caveats

  • Marketplace Pushover actions won't work. The ones we checked are hardwired to api.pushover.net.
  • `--fail-with-body` needs curl 7.76 or later. GitHub-hosted Ubuntu runners have it. It fails the step on a 400 or 429 and prints PushPiper's error.
  • Windows runners default to PowerShell. Add shell: bash to the step.
  • Forks get no secrets. Workflows triggered from a forked repository don't receive PUSHPIPER_TOKEN, so the step fails for outside pull requests.
  • Count your pings. Every notification is one message. Failure-only alerts barely dent 10,000 a month; pinging on every push in a busy repo can.

Sources

Questions and answers

Can I use a Pushover action from the GitHub Marketplace?

Not the ones we checked. desiderati/github-action-pushover, umahmood/pushover-actions and Clivern/pushover-actions all post to api.pushover.net with no way to change the host. A curl step works on any runner that has curl.

How do I get notified only when something fails?

Add if: failure() to the notification step. It then runs only when an earlier step in the same job failed.

How do I keep the token out of the logs?

Store it as a repository secret and hand it to the step through env, like the examples do. GitHub masks secret values in logs.

Does it work on self-hosted runners?

Yes, as long as the runner has bash and curl 7.76 or later and can reach api.pushpiper.com.