Your webhook is configured, you push a commit, and… nothing happens. The failure is in one of exactly three places: GitHub never attempted a delivery, GitHub attempted it and it failed, or it was delivered but your code did nothing visible. The fix is different for each, so the first job is figuring out which one you have.
Repo → Settings → Webhooks → your hook → Recent Deliveries. This log answers the first question instantly:
timed out, failed to connect to host,
certificate errors, or your own 4xx/5xx). Go to §3.Two timing gotchas before you conclude anything: deliveries can take a few minutes to happen and to appear in the log, and deliveries may arrive out of order — use the timestamps in the payload, not arrival order.
All of these are documented, and all of them look like "webhook is broken":
push event is not triggered for that push. Payloads are capped at
25 MB — a bigger event (e.g. a create with many
branches) is silently not delivered.http://localhost:3000
— it's rejected outright ("URL host localhost is not supported"). See §5 for the fix.The Recent Deliveries response tab tells you which one:
timed out — your server must respond 2xx within
10 seconds or GitHub terminates the connection and records a failure.
Respond first, process after (queue the work).failed to connect to host / network — DNS, firewall, or
your server refusing the connection. If you allow-list IPs, GitHub's hook ranges come
from the /meta REST endpoint and change over time.invalid HTTP response — your endpoint returned 4xx/5xx.
Only 2xx counts as success.Isolate infrastructure from code: point the webhook at a capture URL
(button below, or curl https://hookden.pages.dev/new) and hit Redeliver
in Recent Deliveries. If the delivery lands in the bin with a green 2xx, GitHub and the
event are fine — the problem is your server's TLS, network, or response. If it doesn't
land, the problem is on the GitHub side of the fence (§2).
Send one real delivery into a bin and look at what your code actually has to parse:
the X-GitHub-Event header (your router may be ignoring
ping — the very first delivery every new webhook receives is a
ping, not a real event), the X-GitHub-Delivery GUID (log it —
it matches the Recent Deliveries entry), and the exact JSON body. Then
replay that capture against your real endpoint as many times as you need
— no more pushing empty commits to retrigger events. If you verify
X-Hub-Signature-256, the bin shows a ✓/✗ badge when you paste your secret:
verifying GitHub signatures.
GitHub rejects localhost URLs, so give it a capture URL instead and pull deliveries down to your machine:
$ curl https://hookden.pages.dev/cli > hookden && chmod +x hookden $ ./hookden relay YOUR_BIN http://localhost:3000/webhook
Bodies are re-delivered byte-identical, so X-Hub-Signature-256 still
verifies locally. No tunnel, no ngrok, nothing exposed to the internet — details at
/relay.
No signup needed. Or from your terminal: curl https://hookden.pages.dev/new