# How to Send GitHub Release Notifications to a Shared Room

> Use GitHub's release-published event to send one privacy-minimal, retry-safe release alert to a shared PingRoom Room.

- Published: 2026-10-26
- Author: PingRoom
- Category: Developers
- Topics: github release notifications, github release published notification, github webhook notifications, release status notifications
- Canonical: https://pingroom.io/blog/github-release-published-push-notifications
- Cover image: https://pingroom.io/blog/github-release-published-push-notifications-cover.webp
- Cover description: Two PingRoom avatars place one release token beyond a brass gate while Pingo watches beside a closed laptop.

**Use GitHub's custom repository notifications when individual maintainers only need to follow releases. When one selected repository's published release should reach a bounded shared group, add a small GitHub Actions workflow that posts fixed copy to a PingRoom Room.**

The recipe below triggers on `release.published`. GitHub documents that this activity covers stable releases and prereleases published from drafts. GitHub remains the source of truth for the release, notes, assets, and tag. PingRoom carries only the short shared signal.

This is a webhook recipe, not a native GitHub integration. It does not say that a release deployed successfully or works correctly in production.

## Check GitHub's own notifications first

GitHub lets each person [customize a repository subscription](https://docs.github.com/en/subscriptions-and-notifications/concepts/about-notifications) and include releases. Start there when the people who care already use GitHub's inbox, email, or mobile notifications.

| Need                                                                     | Better starting point                              |
| ------------------------------------------------------------------------ | -------------------------------------------------- |
| One maintainer wants release updates for a repository                    | GitHub's custom repository notifications           |
| A selected release publication should reach one shared attention channel | GitHub Actions → PingRoom incoming webhook         |
| Someone needs notes, assets, provenance, or tag details                  | Open the release in GitHub                         |
| A deploy or production incident needs paging and escalation              | Keep the established delivery and incident systems |

A publication event is not a deployment event. If your real question is whether production changed, use the [general CI/CD notification pattern](/blog/ci-cd-deployment-notifications) and the platform that owns that state.

## Create the Room and protect its URL

Create or choose a private Room for the people who need the signal. The Room owner needs **PingRoom Pro** for incoming webhooks.

Open **Settings → Connections → From another app**, add a webhook, leave **Quick Ping** on **Custom message**, and copy its full URL. The [incoming-webhook walkthrough](/blog/webhook-to-push-notification) covers setup; the [webhook reference](/documents/webhooks) carries the current request limits and response contract.

In the GitHub repository, open **Settings → Secrets and variables → Actions** and add a repository secret named `PINGROOM_WEBHOOK_URL`. GitHub's [secret guidance](https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets?tool=webui) explains the repository and environment options.

The URL is a credential. Do not put it in the workflow file, release notes, an artifact, a log, or browser-side code. If it leaks, regenerate it in PingRoom and replace the GitHub secret.

## Add one release-published workflow

Save this as `.github/workflows/release-room-alert.yml` on the repository's default branch. Change `REPOSITORY_LABEL` to a short name that is safe on a lock screen.

```yaml
name: Shared release alert

on:
  release:
    types: [published]

permissions: {}

jobs:
  notify-room:
    runs-on: ubuntu-latest
    env:
      PINGROOM_WEBHOOK_URL: ${{ secrets.PINGROOM_WEBHOOK_URL }}
      REPOSITORY_LABEL: "Selected repository"
      REPOSITORY: ${{ github.repository }}
      RELEASE_ID: ${{ github.event.release.id }}
      RUN_ID: ${{ github.run_id }}
    steps:
      - name: Send shared release alert
        continue-on-error: true
        shell: bash
        run: |
          node <<'NODE'
          const { createHash } = require("node:crypto");

          async function main() {
            const webhookUrl = process.env.PINGROOM_WEBHOOK_URL;
            const label = process.env.REPOSITORY_LABEL;
            const repository = process.env.REPOSITORY;
            const releaseId = process.env.RELEASE_ID;
            const runId = process.env.RUN_ID;

            if (!webhookUrl) throw new Error("Missing PINGROOM_WEBHOOK_URL");
            if (!label || label.length > 80) throw new Error("REPOSITORY_LABEL must be 1–80 characters");
            if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository ?? "")) throw new Error("Invalid REPOSITORY");
            if (!/^\d+$/.test(releaseId ?? "") || !/^\d+$/.test(runId ?? "")) throw new Error("Invalid release or run identity");

            const releaseUrl = `https://github.com/${repository}/releases`;
            const digest = createHash("sha256").update(`${repository}:${releaseId}:${runId}`).digest("hex");
            const eventId = `github-release:${digest}`;
            const payload = {
              action: null,
              title: "GitHub release published",
              message: `${label} · release #${releaseId}`,
              data: { repository, release_id: Number(releaseId), releases_url: releaseUrl },
              correlation_id: eventId,
            };

            const response = await fetch(webhookUrl, {
              method: "POST",
              headers: { Accept: "application/json", "Content-Type": "application/json", "Idempotency-Key": eventId },
              body: JSON.stringify(payload),
              signal: AbortSignal.timeout(10000),
            });

            if (!response.ok) throw new Error(`PingRoom returned HTTP ${response.status}`);
            const accepted = await response.json();
            if (accepted.success !== true) throw new Error("PingRoom did not accept the release alert");
            console.log(`PingRoom accepted ${accepted.notification_id}`);
          }

          main().catch((error) => {
            console.error(error.message);
            process.exit(1);
          });
          NODE
```

GitHub's [`release` event reference](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#release) says the workflow file must exist on the default branch. The narrow `published` filter avoids sending on ordinary edits, deletions, or unpublishing. It also avoids the draft-prerelease gap GitHub documents for the separate `prereleased` activity.

`permissions: {}` gives the workflow's `GITHUB_TOKEN` no repository permissions. There is no checkout, dependency install, build, or execution of release content. The only external credential is the PingRoom URL explicitly placed in the environment.

## Keep the phone copy deliberately small

The recipe forwards a maintainer-supplied label and GitHub's numeric release ID. It does **not** forward the release title, tag, notes, author, assets, commit text, or repository contents.

The URL points to the repository's releases page, where an authorized GitHub user can inspect the actual record. If even the repository name is sensitive, use a neutral label such as **Mobile app** and remove `repository` from `data` after confirming that connected systems do not need it.

![Two PingRoom avatars compare one accepted release token with an identical retry held at a brass gate while Pingo watches.](/blog/github-release-published-push-notifications-1.webp)

_These AI-generated editorial illustrations feature approved PingRoom avatars and Pingo the Pigeon, PingRoom's fictional Chief Marketing Officer. They are not GitHub or PingRoom screenshots and do not depict customers._

[Pingo](/Pingo) has no repository access, private-Room access, or authority to publish a release or send its alert. In the illustration, he is only watching a duplicate token stop at the gate. A human maintainer chooses the repository, workflow, Room, recipients, copy, and failure policy.

## Give one publication event one retry identity

The idempotency key is a SHA-256 digest of the repository, numeric release ID, and workflow run ID. An exact rerun of the same workflow run uses the same key and body, so PingRoom can return the original accepted result instead of creating another Ping. A later publication event receives a new workflow run ID and a new identity.

Do not reuse the same key with different copy. PingRoom rejects a changed body under an existing idempotency key.

The notification step is non-blocking because the release is already published and PingRoom is not its status authority. `continue-on-error: true` leaves the release record untouched if the alert cannot be sent. Teams that need guaranteed escalation should keep their durable release log and paging path.

## Test before relying on the signal

Use a harmless repository or prerelease and check:

1. Publishing a draft creates one **GitHub release published** Ping.
2. Editing the published release does not create another Ping.
3. Rerunning the same workflow does not duplicate the accepted alert.
4. Publishing a later release creates a fresh alert.
5. Removing the secret fails only the non-blocking notification step.

For this article, we ran the exact embedded Node request against a stateful local mock of PingRoom's documented contract. The check covered acceptance, exact replay, changed-body conflict, a fresh publication identity, field limits, headers, privacy exclusions, HTTP rejection, malformed JSON, and missing configuration. It did not use a live GitHub repository, PingRoom Room, phone, or notification receipt.

An HTTP `200` with `success: true` means PingRoom accepted and queued the Ping. Connectivity, notification permissions, Focus settings, Room mutes, and operating-system policy still decide what appears on each phone. Silence is not evidence that no release was published; GitHub remains the record.

If one repository's published releases deserve a shared signal, [create the destination Room and webhook](/app/rooms), add the secret, and test with non-sensitive copy. For a workflow's terminal build result instead, use the separate [GitHub Actions result recipe](/blog/github-actions-push-notifications).

_GitHub is a trademark of GitHub, Inc. PingRoom is not affiliated with or endorsed by GitHub._
