Ngrok Alternative for Webhooks: Test Webhooks Without a Tunnel
Test webhooks without ngrok. Get a permanent URL in one second, inspect every request, and replay to localhost with one CLI command. No tunnel, no authtoken.
Ozer
Developer & Founder of HookSense
If you only use ngrok to receive webhooks, you do not need a tunnel at all. A webhook inspector like HookSense gives you a permanent public URL in about one second — no signup, no authtoken, no agent running in a terminal tab. Incoming webhooks are captured in the cloud with full headers, body, and timing, and one command — npx hooksense listen -p 3000 — forwards them to your local server over plain HTTPS. Your URL never changes between sessions, your request history survives restarts, and you can replay any past event without asking the provider to send it again.
That is the short answer to the search query. The longer answer is about understanding what a tunnel actually gives you, where it fights you when the traffic is webhooks, and when ngrok genuinely remains the better tool. This post covers all three, plus a concrete migration walkthrough. For a side-by-side feature table, see the HookSense vs ngrok comparison page.
Why Developers Reach for Ngrok for Webhooks
The problem is real: Stripe, GitHub, Shopify, Twilio, and every other webhook provider need a public HTTPS URL to deliver events to. Your development server lives on localhost:3000 behind NAT, a router, and possibly a corporate firewall. The provider cannot reach it.
Ngrok solves this with a tunnel. The agent on your machine opens a persistent outbound connection to ngrok's edge, ngrok hands you a public URL, and traffic hitting that URL is piped down the tunnel to your local port. It works, it is well documented, and it is the first answer on almost every Stack Overflow thread about local webhook testing.
The catch is that a tunnel is a general-purpose tool being used for a narrow job. Webhooks have specific needs — durable URLs, durable history, the ability to re-send a request — and a raw tunnel provides none of them.
Where Ngrok Hurts for Webhook Work
1. A New Random URL Every Session
On the free tier, every ngrok http 3000 produces a fresh randomly-generated URL. That URL is registered in your Stripe dashboard, your GitHub repo settings, your Shopify app config. Restart your laptop, restart the tunnel, and every one of those registrations is now pointing at a dead address. The fix is logging into each provider dashboard and pasting the new URL — every single session. Reserved static domains exist, but they are a paid feature, and you still carry the rest of the limitations below.
2. Request History Dies with the Tunnel
Ngrok's local web interface at localhost:4040 shows requests while the agent runs. Close the terminal, and that history is gone. If Stripe delivered a webhook at 6pm and you opened your laptop at 9am, there is nothing to look at — the tunnel was down, so the request either failed at the provider or vanished. Debugging an intermittent webhook failure with no persistent record is guesswork.
3. No Replay
The single most useful operation in webhook development is re-sending a request you already received. Tweak your handler, replay the exact same payload, see if it passes. With a tunnel, there is no stored request to replay. Your options are clicking "resend" in the provider dashboard (if the provider offers one) or re-triggering the real event — creating another test payment, pushing another commit — just to exercise one code path.
4. Setup Friction
Ngrok now requires an account and an authtoken before the agent will start a tunnel. That is reasonable for an infrastructure tool, but it is friction when you just want to see what a webhook payload looks like. Add config files, agent updates, and per-machine token setup, and the "quick tunnel" has a real onboarding cost — multiplied across every teammate and every CI environment.
5. Your Machine Has to Be Up — and Exposed
A tunnel only captures traffic while it is running, and while it runs, your local port is reachable from the public internet. For webhook testing you rarely want either property. You want the events captured whether or not your laptop is awake, and you want nothing on your machine exposed at all.
The Inspector Approach: Capture First, Forward Second
A webhook inspector flips the architecture. Instead of piping traffic through your machine, the public endpoint lives in the cloud and stores everything it receives. Your machine becomes an optional consumer of that stream rather than a required hop in it.
Concretely, with HookSense:
- Permanent URL, instantly. Open hooksense.com and you have a working endpoint in about one second, no signup. Register it with your provider once; it never changes.
- Every request is stored. Full headers, raw body, query string, timing — captured whether your laptop is on or not, streamed live to the dashboard over WebSocket when you are watching.
- Replay anything. Select any captured request and re-send it to your local server or any URL, with optional edits to headers and body before sending. See the replay docs for details.
- Signature verification built in. Verify Stripe, GitHub, and Shopify signatures — or any custom HMAC scheme — directly in the UI, so you know whether a 400 is your bug or a wrong secret before you write a line of handler code.
- Encrypted at rest. Captured payloads are encrypted with AES-256-GCM, which matters when the payloads are payment events and customer data.
Forwarding to Localhost — Without a Tunnel
"But I still need the webhook to hit my local handler," you say. Correct, and this is where the CLI replaces the tunnel:
npx hooksense listen -p 3000
The CLI opens an outbound HTTPS connection to HookSense, pulls each captured event as it arrives, and POSTs it to your server on port 3000 with the original headers and body intact. The flow of data is the same as a tunnel — provider to cloud to localhost — but the mechanics are different in ways that matter:
- No inbound connection to your machine. Nothing is exposed. Firewalls and corporate VPNs do not care, because all traffic is ordinary outbound HTTPS.
- No authtoken, no install.
npxruns it directly; there is no agent to configure. - Events are not lost when the CLI is down. They are already captured in the cloud. Start the CLI later, or replay the ones you missed.
Full flags and options are in the CLI documentation. If your specific provider is Stripe, the workflow is covered end-to-end in how to test Stripe webhooks locally.
When Ngrok Is Still the Right Tool
Honesty section. An inspector is not a tunnel, and there are jobs where you genuinely need a tunnel:
- Demoing a full app. If a client needs to click around the UI running on your laptop, you need real bidirectional HTTP to your machine. That is exactly what ngrok is for.
- Non-webhook HTTP traffic. OAuth flows where a browser must load pages from your local server, mobile apps hitting a local API, testing a site on a real phone — tunnel territory.
- TCP tunnels. SSH, databases, game servers, anything that is not HTTP. An inspector cannot help here at all.
- Responses that matter. A webhook inspector acknowledges requests itself. If the provider's behavior depends on a response body your code generates in real time during the original request, you need the request to actually reach your code first — a tunnel does that.
The honest framing: ngrok is a general-purpose tunnel that is mediocre at webhooks. HookSense is a webhook tool that does not pretend to be a tunnel. Pick per job.
Migration Walkthrough: From Ngrok to HookSense
Switching takes about five minutes per provider:
- Create an endpoint. Go to hooksense.com and grab a URL — it takes about a second and works without an account. Sign up free when you want the URL tied to you and 14 days of history.
- Update the provider. In Stripe, GitHub, Shopify, or wherever, replace your old ngrok URL with the HookSense URL. This is the last time you will ever paste a webhook URL into that dashboard.
- Trigger a test event. Send a test webhook from the provider. Watch it appear live in the HookSense dashboard with full headers and body.
- Verify the signature. Paste your signing secret and confirm verification passes before touching your handler. This isolates "wrong secret" from "broken code" on day one.
- Forward to localhost. Run
npx hooksense listen -p 3000(swap in your port). Events now hit your local handler exactly as they would in production. - Develop with replay. When your handler fails, fix the code and replay the same captured request instead of re-triggering the event. Repeat until it returns 200.
- Retire the tunnel. Remove the ngrok startup step from your dev notes and onboarding docs. New teammates need one URL and one npx command.
What It Costs
The free Catch plan covers solo webhook debugging: 3 endpoints, 300 requests a day, 14-day retention, and 5 replays a month. The Hook plan at 19 dollars a month adds 15 endpoints, 5,000 requests a day, 30-day retention, HMAC verification, unlimited replays, and 3 team seats. Sense at 49 dollars a month brings unlimited endpoints, 50,000 requests a day, 90-day retention, custom domains, and 10 seats. Full details on the pricing page.
If your ngrok usage is really webhook usage, try the swap: one permanent URL, one CLI command, and every request you have ever received sitting there waiting to be replayed.
Related posts
Try HookSense Free
Inspect, debug, and replay webhooks in real-time. No credit card required.
Get Started Free