Quick Answer
During development, use Requex to inspect raw payloads without a tunnel. When you need to test your actual handler locally, use ngrok or smee.io to forward events to localhost.
Best Webhook Testing Tools for Node.js Developers
A practical comparison of Requex, ngrok, smee.io, and localtunnel — plus the Express middleware patterns you'll use alongside them.
Tool Comparison
| Tool | Install Required | Forwards to Localhost | Payload Inspector | Persistent URL | Cost |
|---|---|---|---|---|---|
| Requex | No | Via forwarding rules | Yes — full UI | Yes (auth required) | Free |
| ngrok | Yes | Yes (native tunnel) | Yes (localhost:4040) | Paid plan | Free / Paid |
| smee.io | npm client (optional) | Yes (via client) | Basic | Yes | Free |
| localtunnel | Yes (npx) | Yes (native tunnel) | No | Subdomain request | Free |
Requex — Inspect Without a Running Server
The biggest advantage of Requex in a Node.js workflow is that you don't need a running server to start inspecting payloads. Get a URL, point a webhook source at it, and see exactly what the provider sends — headers, body, method, query params — before writing a single line of Express code.
Once you know the payload structure, you can write your handler with confidence. Requex also supports forwarding rules, so you can later proxy incoming events to your local Express server for end-to-end testing.
ngrok — The Standard for Local Express Testing
ngrok is the most widely used tool for exposing a local Express server to the internet. Run ngrok http 3000 and get a public HTTPS URL that forwards directly to localhost:3000.
The ngrok dashboard at localhost:4040 shows all incoming requests with replay capability. The limitation on the free tier is that the subdomain changes each session, which means you need to update the webhook URL in your provider's dashboard on every restart.
smee.io — The npm-Native Option
smee.io is built by GitHub and is particularly well-suited to GitHub webhook testing. It works via a persistent channel URL and a small npm client (smee-client) that you can add to your package.json dev dependencies.
Unlike ngrok, smee.io uses Server-Sent Events (SSE) rather than a binary tunnel daemon, which means lower overhead and easier CI integration. The payload viewer is more limited than ngrok or Requex, but for GitHub webhooks it's the simplest zero-friction option.
Express Webhook Middleware Patterns
Regardless of which tunneling tool you use, your Express webhook handler needs to capture the raw body for HMAC signature verification. Use this pattern:
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString('utf8')
}
}))
app.post('/webhook', (req, res) => {
const sig = req.headers['x-hub-signature-256']
const hmac = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET)
hmac.update(req.rawBody)
const expected = 'sha256=' + hmac.digest('hex')
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(403).send('Invalid signature')
}
res.sendStatus(200)
})Related Resources
Start Inspecting Payloads Now
Generate a free endpoint and see exactly what your webhook provider sends before writing a line of handler code.
Open Requex →