GitHub-Webhooks: Pushes, Releases und rote Actions aufs Handy
20. Juli 2026 · aktualisiert im Oktober 2026 · 6 Min. Lesezeit
In GitHub heißen zwei verschiedene Mechanismen „Webhook“, und die falsche Wahl ist der Grund, warum die meisten Setups komplizierter werden als nötig. Hier der Unterschied, die Events, die sich lohnen, und wie du jedes davon mit einem wiedererkennbaren Sound aufs Handy bekommst.
Repository-Webhooks vs. GitHub Actions
Das wird ständig verwechselt, also 60 Sekunden dafür:
- Ein Repository-Webhook wird unter Settings → Webhooks am Repo (oder an der Organisation) eingerichtet. GitHub postet ein JSON-Payload an deine URL, sobald ein abonniertes Ereignis eintritt. Es läuft nichts in der CI, es kostet keine Minuten, und er feuert auch für Dinge, die Actions schlecht sehen kann – ein neuer Stern, ein Issue-Kommentar, ein gelöschter Branch.
- Ein GitHub-Actions-Step läuft innerhalb eines Workflows. Er feuert nur, wenn ein Workflow läuft, kostet Actions-Minuten, hat dafür aber den vollen Job-Kontext: welcher Job fehlgeschlagen ist, an welchem Step, auf welchem Commit.
Die Faustregel: Willst du wissen, dass im Repo etwas passiert ist, nimm einen Repository-Webhook. Willst du wissen, dass in deiner Pipeline etwas passiert ist, häng einen Step an den Workflow. Viele greifen zu Actions, weil es vertraut ist, und wundern sich dann, dass sie über ein neues Issue nicht benachrichtigt werden.
Weg 1: Repository-Webhook direkt aufs Handy
Ein Webhooky-Endpunkt ist eine URL, die jeden POST annimmt und daraus eine Push-Benachrichtigung macht. GitHub braucht eine Payload-URL. Das ist die ganze Integration – ohne Server, ohne Actions-Minuten:
- Leg in der Webhooky-App einen Endpunkt an. Benenn ihn nach dem Repo, wähl einen Sound, kopier die URL.
- Öffne im Repository Settings → Webhooks → Add webhook.
- Füg die URL als Payload URL ein, setz Content type auf
application/jsonund wähl die Events aus.
GitHubs Payloads sind groß und je Event unterschiedlich. Webhooky parst sie nicht: Weil der Body kein Feld title oder message hat, greift der Fallback auf Titel, Text und Sound vom Endpunkt. Du bekommst sofort „im Repo X ist etwas passiert“ – mit eigenem Klang.
Die Events, die sich am ehesten lohnen:
push– Commits sind auf einem Branch gelandetpull_request– geöffnet, geschlossen, gemerged, Review angefragtissues– jemand hat ein Issue geöffnet oder geschlossenrelease– ein Release wurde veröffentlichtworkflow_run– ein Workflow ist fertig, inklusive Ergebnisdeployment– ein Deployment wurde angelegt
Jede Zustellung bringt Header mit, die man kennen sollte: X-GitHub-Event sagt, welches Event es war, X-GitHub-Delivery ist eine eindeutige ID für diese Zustellung, und X-Hub-Signature-256 enthält einen HMAC-SHA256-Hex-Digest des Bodys mit deinem Secret als Schlüssel – allerdings nur, wenn du ein Secret gesetzt hast. (X-Hub-Signature ist die SHA-1-Variante, aus Kompatibilitätsgründen erhalten; nimm die 256er.) Webhooky prüft diese Signatur nicht – wer deine Endpunkt-URL kennt, könnte eine Benachrichtigung auslösen. Bei einem Build-Alert ist das lästig, kein Risiko; wenn es zählt, nimm Weg 3.
Weg 2: ein Step in GitHub Actions
Wenn du die Details des Fehlschlags willst und nicht nur die Tatsache, häng das als letzten Step an einen Job. Die Bedingung if: failure() sorgt dafür, dass er nur läuft, wenn vorher etwas fehlgeschlagen ist:
- name: Notify on failure
if: failure()
run: |
curl -X POST "https://api.webhooky.app/${{ secrets.WEBHOOKY_KEY }}" \
-H "Content-Type: application/json" \
-d "{\"title\":\"❌ CI fehlgeschlagen\",
\"message\":\"${{ github.repository }} · ${{ github.workflow }} · ${{ github.ref_name }}\",
\"sound\":\"buzzer\"}"
Leg den Endpunkt-Key unter Settings → Secrets and variables → Actions ab und nicht in die Workflow-Datei, damit er nicht über einen Fork oder ein öffentliches Repo abfließt.
Zwei Varianten lohnen sich. Nimm if: success() mit einem leiseren Sound am Deploy-Job, dann bekommt ein erfolgreiches Production-Deploy seine eigene Bestätigung. Und nimm if: always() bei einem Nightly-Job – denn was du bei einem geplanten Workflow wirklich wissen willst, ist der Moment, in dem er stillschweigend gar nicht mehr gelaufen ist.
Weg 3: ein kleiner Handler, für Details und Signaturprüfung
Wenn du „PR #412 von Anna gemerged“ willst statt „irgendwas ist passiert“, musst du das Payload parsen – und wenn du das ohnehin tust, prüf auch gleich die Signatur:
import crypto from "node:crypto";
export async function onGitHubWebhook(req, res) {
const sig = req.get("X-Hub-Signature-256") ?? "";
const mac = "sha256=" + crypto
.createHmac("sha256", process.env.GH_WEBHOOK_SECRET)
.update(req.rawBody) // der ROHE Body, vor JSON.parse
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(mac))) {
return res.sendStatus(401);
}
res.sendStatus(200);
if (req.get("X-GitHub-Event") !== "pull_request") return;
const { action, pull_request: pr, repository } = req.body;
if (action !== "closed" || !pr.merged) return;
await fetch(process.env.WEBHOOKY_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: "🚀 PR gemerged",
message: `${repository.full_name} #${pr.number} von ${pr.merged_by.login}`,
sound: "level_up_2",
}),
});
}
Zwei Details verursachen hier die meisten Fehler: Berechne den HMAC über den rohen Body, denn erneutes Serialisieren von geparstem JSON verändert die Bytes und die Signatur passt nie. Und vergleiche timing-sicher statt mit ===.
Ein Sound pro Signal
Das ist der Teil, der daraus echten Nutzen macht statt nur mehr Lärm. Leg pro Signal einen Endpunkt an und gib jedem einen Sound mit Bedeutung – Buzzer für einen fehlgeschlagenen Build, etwas Leises und Angenehmes für ein erfolgreiches Deploy, einen eigenen Ton für ein neues Issue. Nach ein paar Tagen liest du die Benachrichtigung nicht mehr: Eine rote Pipeline klingt wie eine rote Pipeline. 40 Sounds stehen zur Wahl, pro Endpunkt einstellbar oder pro Nachricht über das Feld sound überschreibbar, und jeder Endpunkt führt seine eigene Historie.
GitLab, Jenkins und der Rest
Dasselbe Zwei-Wege-Muster gilt überall. GitLab hat Projekt-Webhooks unter Settings → Webhooks plus Pipeline-Jobs – siehe GitLab-Webhooks. Jenkins kann aus einem Post-Build-Step posten, behandelt in Jenkins-Build-Benachrichtigungen. Für Deploy-Plattformen gibt es Vercel und Netlify.
Webhooky holen
100 Benachrichtigungen gratis pro Monat, kein Konto, Endpunkt in zwei Minuten eingerichtet.
Häufige Fragen
Was ist der Unterschied zwischen einem GitHub-Webhook und einer GitHub Action?
Ein Repository-Webhook wird unter Settings → Webhooks eingerichtet und postet ein Payload an deine URL, wenn im Repo etwas passiert – es läuft keine CI und es werden keine Actions-Minuten verbraucht. Ein GitHub-Actions-Step läuft in einem Workflow, feuert also nur, wenn ein Workflow läuft, hat dafür aber den vollen Job-Kontext.
Wie bekomme ich eine Benachrichtigung, wenn eine GitHub Action fehlschlägt?
Häng einen letzten Step mit if: failure() an den Job, der an eine Benachrichtigungs-URL postet. Alternativ abonnierst du einen Repository-Webhook auf das Event workflow_run, das das Ergebnis des Workflows mitliefert.
Wie prüfe ich die Signatur eines GitHub-Webhooks?
Setz ein Secret am Webhook. GitHub sendet dann X-Hub-Signature-256, einen HMAC-SHA256-Hex-Digest des Request-Bodys mit diesem Secret als Schlüssel. Berechne ihn über den rohen Body vor dem JSON-Parsen neu und vergleiche timing-sicher.
Welche GitHub-Webhook-Events gibt es?
Viele, aber die meistgenutzten sind push, pull_request, issues, release, workflow_run und deployment. Welches Event eine Zustellung betrifft, steht im Header X-GitHub-Event.