How to Test Webhooks Locally: A Complete Guide
Testing webhooks locally is one of the most common challenges in API development. Webhook providers like Stripe, GitHub, and Shopify need a publicly accessible URL to send events to — but your localhost:3000 isn't reachable from the internet.
This guide covers the best approaches to solve this problem.
The Challenge
When you register a webhook URL with a service like Stripe, here's what happens:
- An event occurs (e.g., a payment succeeds)
- Stripe sends an HTTP POST to your registered URL
- Your server processes the event
The problem: during development, your server runs on localhost. Stripe can't reach localhost:3000/webhooks/stripe from their servers.
Method 1: Use a Webhook Gateway (Recommended)
A webhook gateway like Mitte gives you a persistent public URL that receives webhooks and forwards them to your local server — or any destination.
Step-by-Step with Mitte
1. Create an endpoint
Sign up at mitte.run and create a new endpoint. You'll get a URL like:
https://hook.mitte.run/e/your-endpoint-id
2. Set your forwarding destination
Configure the endpoint to forward to your local development server:
http://localhost:3000/api/webhooks/stripe
For local forwarding during development, you'll need a tunneling tool or run Mitte's webhook debugger tool.
3. Register the URL with your webhook provider
In Stripe's dashboard (or any webhook provider), set the webhook URL to your Mitte endpoint URL.
4. Monitor in real-time
Open Mitte's dashboard to see webhook events streaming in real-time. Every request shows:
- Full headers and body
- Response status and timing
- Error details if delivery failed
- AI-powered error explanations (Pro)
Why This Approach Is Best
- ✅ Persistent URL — No new URL every time you restart your dev server
- ✅ Full history — All events are logged even if your local server is down
- ✅ Auto-retries — Failed deliveries are automatically retried
- ✅ Team-friendly — Share endpoints and logs with teammates
- ✅ AI debugging — Get instant explanations when things break
Method 2: Use a Tunneling Tool
Tunneling tools create a secure tunnel from a public URL to your local machine.
Using ngrok
# Install ngrok
brew install ngrok # or download from ngrok.com
# Start a tunnel to your local server
ngrok http 3000
ngrok will give you a URL like https://abc123.ngrok-free.app that forwards to localhost:3000.
Pros:
- Quick setup
- Traffic inspection UI
- Request replay
Cons:
- URL changes on every restart (free plan)
- No auto-retries
- No payload transforms
- Not suitable for production
Using Cloudflare Tunnel
# Install cloudflared
brew install cloudflared
# Quick tunnel (no account needed)
cloudflared tunnel --url http://localhost:3000
Pros:
- Free
- DDoS protection
- Stable URLs with named tunnels
Cons:
- More complex setup for persistent tunnels
- No webhook-specific features
Method 3: Use Webhook Provider CLI Tools
Many webhook providers offer CLI tools that forward events to localhost:
Stripe CLI
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login
stripe login
# Forward events to your local server
stripe listen --forward-to localhost:3000/api/webhooks/stripe
GitHub CLI (with smee.io)
# Install smee client
npm install -g smee-client
# Create a channel at smee.io, then:
smee -u https://smee.io/your-channel -t http://localhost:3000/api/webhooks/github
Pros:
- Official tooling, well-documented
- Tight integration with the specific provider
Cons:
- Provider-specific — need different tools for each service
- Only for development
- Limited to that provider's events
Method 4: Use Mitte's Webhook Debugger
For quick testing without any setup, use Mitte's free Webhook Debugger:
- Visit the tool page — you get an instant URL
- Send test webhooks to that URL (via
curl, Postman, or your webhook provider) - See requests appear in real-time in your browser
- Inspect headers, body, query params, and timing
This is the fastest way to verify that a webhook provider is sending the right payload before writing any handling code.
Best Practices for Webhook Testing
1. Always Verify Signatures
import crypto from 'crypto'
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)
}
2. Return 200 Quickly, Process Async
app.post('/webhooks/stripe', async (req, res) => {
// Acknowledge receipt immediately
res.status(200).json({ received: true })
// Process the event asynchronously
processWebhookEvent(req.body).catch(console.error)
})
3. Handle Idempotency
Webhooks can be delivered more than once. Use the event ID to deduplicate:
const processedEvents = new Set<string>()
async function processWebhookEvent(event: WebhookEvent) {
if (processedEvents.has(event.id)) {
return // Already processed
}
processedEvents.add(event.id)
// ... handle the event
}
4. Test Error Scenarios
Don't just test the happy path. Simulate:
- Timeouts — What if your server takes too long to respond?
- Invalid signatures — Does your verification code reject bad signatures?
- Duplicate deliveries — Does your idempotency logic work?
- Malformed payloads — What if the body isn't valid JSON?
Summary
| Method | Setup Time | Best For | Production-Ready |
|---|---|---|---|
| Mitte (gateway) | 2 min | Full webhook workflow | ✅ |
| ngrok (tunnel) | 1 min | Quick local testing | ❌ |
| Provider CLI | 5 min | Single-provider testing | ❌ |
| Webhook Debugger | 0 min | Quick payload inspection | ❌ |
For most teams, using a webhook gateway during development and in production gives you the best developer experience — persistent URLs, full logging, auto-retries, and no URL changes every time you restart.
Ready to simplify your webhook development? Get started with Mitte →
How to Use MCP to Debug Webhooks with AI
Step-by-step guide to debugging webhook failures using MCP and AI assistants. Connect Cursor, VS Code Copilot, or Claude to your webhook logs and fix issues in seconds.
Top 5 ngrok Alternatives for Webhook Testing in 2026
Looking for an ngrok alternative for webhook development? Compare Mitte, Cloudflare Tunnel, localtunnel, Expose, and webhook.site for webhook testing and delivery.