You push a commit, GitHub says the webhook was sent, and Jenkins does… nothing. This failure has a short list of causes, and they're almost always one of these six — in this order. Two of them (the trailing slash and the checkbox) account for the vast majority of cases.
Open your repository on GitHub → Settings → Webhooks → your hook → Recent Deliveries. Every attempt is listed with the response code Jenkins gave back. This splits the problem in half immediately:
Not sure what GitHub is even sending? Point a second webhook at a capture URL
(curl https://hookden.pages.dev/new) and push again — you'll see the exact
X-GitHub-Event, headers, and payload next to GitHub's view of your
Jenkins deliveries.
/github-webhook/, not /github-webhookThe payload URL must be your Jenkins base URL plus /github-webhook/
— with the trailing slash:
https://jenkins.example.com/github-webhook/
Without the slash, Jenkins answers 302 Found (a redirect to the
slashed URL). GitHub's webhook deliveries don't follow redirects — a 302 counts as a
completed (failed) delivery and no build ever triggers. In Recent Deliveries this is
unmistakable: every delivery shows response 302. Set the content type to
application/json while you're there.
Receiving the webhook isn't enough — the job has to opt in. In the job's configuration under Build Triggers, check GitHub hook trigger for GITScm polling (older Jenkins called it "Build when a change is pushed to GitHub"). The option only appears when the GitHub plugin is installed, and the job's Source Code Management section must be set to Git with the same repository URL that's sending the hook — the plugin matches incoming events against each job's configured repo.
This trigger doesn't build unconditionally — an incoming push event kicks the git plugin's polling for jobs that match the repository. Polling then decides whether there's anything to build, which is where the silent failures live:
*/main and you pushed feature/x, polling finds no relevant
change and no build starts. Widen the specifier or push to a matching branch.git@github.com:org/repo.git vs
https://github.com/org/repo.git in the SCM section can prevent the event
from matching the job at all. Make the SCM URL point at the same repository the hook
comes from.Jenkins shows its side of the story in the job's GitHub Hook Log (left sidebar on the job page once the trigger is enabled): it records the last received hook event and the polling decision. "No changes" there = delivery worked, polling matched nothing.
This means the payload URL points at an endpoint that requires CSRF protection —
usually /job/NAME/build or /job/NAME/buildWithParameters.
Those endpoints are for authenticated API calls (token + crumb), not for GitHub.
The fix isn't to disable CSRF protection — it's to use the endpoint that's designed
for webhooks: /github-webhook/ handles GitHub deliveries without a
crumb.
If Jenkins runs on localhost, a home machine, or an internal network,
GitHub's delivery fails with a timeout or connection error — GitHub.com can only
deliver to public HTTPS endpoints. You don't have to expose Jenkins to the internet
to fix this. Give GitHub a capture URL as the payload URL and relay deliveries to
your internal Jenkins:
$ curl -s https://hookden.pages.dev/cli -o hookden && chmod +x hookden $ curl https://hookden.pages.dev/new $ ./hookden relay YOUR_BIN http://localhost:8080/github-webhook/
The relay re-delivers each request with a byte-identical body, so if you've
configured a webhook shared secret, Jenkins's X-Hub-Signature check
still verifies. Jenkins stays private; GitHub sees a public endpoint that always
answers 200. Details: webhooks to localhost
without a tunnel.
A Multibranch Pipeline or GitHub Organization folder doesn't show the "GitHub hook
trigger" checkbox — and doesn't need it. Webhook events (same
/github-webhook/ endpoint) trigger branch indexing via the
job's GitHub branch source: new branches and PRs are discovered and built according
to the branch source's discovery settings. If pushes aren't triggering, re-run
Scan Repository Now and read its log — it tells you which branches
were discovered and why any were skipped. And if the scan builds things but webhooks
don't, you're back to causes 0, 1, and 5: check Recent Deliveries for what Jenkins
answered.
/github-webhook/ — trailing slash presentapplication/json, hook Active, push events selectedSame class of problem elsewhere? See GitHub webhook not triggering and GitLab webhook not working.
No signup needed. Or from your terminal: curl https://hookden.pages.dev/new