Building a CI/CD tool? A GitHub bot? A deployment system? You'll need to handle GitHub webhooks. Push events, pull request updates, issue comments — GitHub sends webhooks for almost everything.
The challenge is testing them locally. You can't exactly ask your team to "push some commits so I can debug this webhook handler."
Why GitHub Webhooks Are Different
GitHub webhooks have some unique characteristics:
- Event variety — Over 40 different event types, each with different payloads
- Large payloads — Push events can include full commit data, diffs, and file changes
- Signature verification — GitHub signs webhooks with HMAC-SHA256
- Hard to trigger — You can't easily create a "test push" without actually pushing
To test a push webhook, you need to push code. To test a PR webhook, you need to create a PR. This gets old fast when you're debugging.
Setting Up GitHub Webhooks for Local Development
Here's how to set up a workflow that doesn't require constant pushing:
Create a capture endpoint
Sign up at hookreplay.dev and create an endpoint. You'll get a stable URL:
https://hookreplay.dev/hook/your-unique-id
Configure GitHub
In your repository, go to Settings → Webhooks → Add webhook:
- Payload URL: Your HookReplay URL
- Content type: application/json
- Secret: Generate one for HMAC verification
- Events: Select the events you need (or "Send me everything")
Trigger some events
Do the actions you want to test: push a commit, create a PR, open an issue. Each event is captured and stored.
Pro tip: GitHub also lets you redeliver past webhooks from Settings → Webhooks → Recent Deliveries. Use this to capture events without doing the actual action.
Replay to localhost
Connect the CLI:
$ npx hookreplay ● hookreplay> connect ✓ Connected! Waiting for replay requests...
Now replay any captured webhook to your localhost. Push event? Replay it 50 times while you debug. No more creating fake commits.
Common GitHub Webhook Events
Here are the events you'll most likely need to handle:
| Event | Trigger | Common use case |
|---|---|---|
push |
Commits pushed | CI/CD, deployments, notifications |
pull_request |
PR opened, closed, merged | Code review bots, CI checks |
issues |
Issue opened, closed, edited | Issue trackers, bots |
issue_comment |
Comment on issue or PR | Command bots (/deploy, /approve) |
release |
Release published | Auto-deployments, notifications |
workflow_run |
GitHub Action completed | CI status tracking |
Verifying GitHub Signatures
GitHub signs webhooks using HMAC-SHA256 with your webhook secret.
The signature is in the X-Hub-Signature-256 header.
const crypto = require('crypto');
function verifyGitHubSignature(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
During development, you can skip verification or use the same secret that GitHub is using to sign the webhooks.
Testing Different Scenarios
With payload editing, you can test scenarios that are hard to create naturally:
- Force push — Set
forced: truein the push payload - PR from fork — Modify the head repository details
- Deleted branch — Set
deleted: true - Large commit batch — Add more commits to the array
- Specific file changes — Edit the
added,modified,removedarrays
Instead of creating real scenarios in your repo (which pollutes your git history), just edit the payload and replay.
Building GitHub Bots
If you're building a bot that responds to comments (like /deploy commands),
capture-and-replay is essential. You don't want to spam your PRs with test comments.
- Capture one real
issue_commentevent - Edit the comment body to test different commands
- Replay until your bot handles all cases correctly
Your PR stays clean, your bot gets tested.
Summary
GitHub webhook development doesn't have to mean constantly pushing commits or creating PRs. Capture the events once, then:
- Replay them unlimited times while debugging
- Edit payloads to test edge cases
- Build and test bots without spamming your repos
- Keep your git history clean
Focus on writing your webhook handler, not on creating test events.