GitHub Webhook Handler
raw JSON →github-webhook-handler is a Node.js library providing a minimalist handler or middleware for processing GitHub Webhooks. It simplifies the process of receiving and verifying webhook requests, acting as an EventEmitter for various GitHub events such as `push` or `issues`. The current stable version is 2.1.1, released in April 2026, following a major v2.0.0 release in January 2026 that introduced ESM support, promises, and updated Node.js requirements (>=20). This package differentiates itself by focusing specifically on GitHub webhooks, handling SHA-1 HMAC signature verification and event parsing, allowing developers to quickly integrate webhook processing into their Node.js applications without dealing with low-level HTTP request body parsing and security checks. It features a straightforward API for creating a handler function that can be integrated into standard Node.js HTTP servers, designed for developers who need a robust, event-driven way to react to GitHub repository activity.
Common errors
error TypeError: createHandler is not a function ↓
import createHandler from 'github-webhook-handler' and ensure your package.json has "type": "module" if running in Node.js >=12, or use a .mjs file extension. error Error: secret must be given ↓
secret option: createHandler({ path: '/webhook', secret: 'your_github_secret' }). This secret must match the one configured in GitHub. error Error: signature does not match ↓
secret value in your code precisely matches the 'Secret' configured in your GitHub webhook settings. Also, ensure the content type in GitHub is application/json. error ERR_HTTP_HEADERS_SENT ↓
next callback only handle the response once. For instance, if an event listener processes the request, it should handle res.end(), and the next callback should be designed not to interfere if the request was successfully handled by the webhook. Warnings
breaking Version 2.0.0 introduced significant breaking changes: it switched to ESM-only (removing CommonJS support), updated its internal dependencies, and raised the minimum required Node.js version to 20. Applications using `require()` or older Node.js runtimes will fail. ↓
gotcha The `secret` option passed to `createHandler` is critical for verifying the `X-Hub-Signature` HMAC sent by GitHub. If the secret is missing, incorrect, or doesn't match the one configured in GitHub, all webhook requests will be rejected. ↓
gotcha GitHub webhook settings must be configured to send payloads as `application/json`. The library does not support `application/x-www-form-urlencoded` content types, and requests with this type will not be processed correctly. ↓
gotcha The handler is an `EventEmitter` and will emit an `'error'` event for various issues (e.g., signature mismatch, invalid path). If no listener is registered for this event, Node.js will throw an unhandled `Error` and potentially crash the application. ↓
Install
npm install github-webhook-handler yarn add github-webhook-handler pnpm add github-webhook-handler Imports
- createHandler wrong
const createHandler = require('github-webhook-handler')correctimport createHandler from 'github-webhook-handler' - HandlerOptions
import type { HandlerOptions } from 'github-webhook-handler' - events wrong
const events = require('github-webhook-handler/events.json')correctimport events from 'github-webhook-handler/events.json' with { type: 'json' }
Quickstart
import http from 'node:http'
import createHandler from 'github-webhook-handler'
// Ensure these are secure in a production environment
const GITHUB_WEBHOOK_PATH = process.env.GITHUB_WEBHOOK_PATH ?? '/webhook'
const GITHUB_WEBHOOK_SECRET = process.env.GITHUB_WEBHOOK_SECRET ?? 'myhashsecret'
const LISTEN_PORT = parseInt(process.env.PORT ?? '7777', 10)
const handler = createHandler({
path: GITHUB_WEBHOOK_PATH,
secret: GITHUB_WEBHOOK_SECRET
})
http.createServer((req, res) => {
handler(req, res, (err) => {
res.statusCode = 404
res.end('no such location')
})
}).listen(LISTEN_PORT, () => {
console.log(`Server listening on port ${LISTEN_PORT} for GitHub webhooks at path ${GITHUB_WEBHOOK_PATH}`)
})
handler.on('error', (err) => {
console.error('Error handling webhook:', err.message)
})
handler.on('push', (event) => {
console.log('Received a push event for %s to %s',
event.payload.repository.name,
event.payload.ref)
// Add your logic here to react to a push event
})
handler.on('issues', (event) => {
console.log('Received an issue event for %s action=%s: #%d %s',
event.payload.repository.name,
event.payload.action,
event.payload.issue.number,
event.payload.issue.title)
// Add your logic here to react to an issue event
})
console.log('GitHub webhook handler initialized.')