FeaturesGuidesBlogDocumentationFreeGet Started

Test Webhooks Locally

Pillar hub: choose Stripe CLI vs HTTPS tunnel, pick your provider from the table, and register a public webhook URL on localhost.

The webhook testing problem

Webhooks are HTTP POST requests that external services send to your server when events occur — a payment succeeds, a pull request opens, an order ships. Your local dev server listens on localhost, which is unreachable from the internet. Without a public URL, providers cannot deliver events to your machine.

Two proven approaches solve this: provider CLI tools that forward events locally, and HTTPS tunnels that give providers a real URL to POST to.

Pick a provider below — each linked guide opens with provider-specific verification steps so you do not repeat this hub verbatim.

Two approaches compared

ApproachHow it worksBest when
Provider CLITool receives events and forwards to localhostQuick iteration, signature testing
HTTPS tunnelPublic URL forwards to your local handlerTesting exact production URL format, dashboard "Send test webhook"

Both are valid. Many teams use the CLI for day-to-day development and a tunnel when validating the full integration path.

Quick start with LocalToLink

1. Start your app with a webhook handler route (e.g. /api/webhooks/stripe):

npm run dev

2. Start the tunnel in a second terminal:

npx localtolink --port 3000

3. Register the webhook URL in your provider's dashboard:

https://k7m2x9p4q1.localtolink.com/api/webhooks/stripe

Replace k7m2x9p4q1 with the 10-character subdomain LocalToLink assigns.

4. Trigger an event from the provider (test button, real action, or CLI) and watch your local logs.

Some automated clients may reach your app differently than a first-time browser visit. Webhook delivery is server-to-server — no special headers needed for normal provider POSTs.

Provider-specific guides

Each provider has signature verification rules and dashboard quirks. Follow the dedicated guide for your stack:

ProviderGuideTypical webhook path
StripeTest Stripe Webhooks Locally/api/webhooks/stripe
GitHubTest GitHub Webhooks on Localhost/api/github/webhook
ShopifyTest Shopify Webhooks in Development/webhooks/shopify
TwilioTest Twilio Webhooks Locallyapp route twilio/voice
n8nn8n OAuth and Webhooks on Localhost/webhook/your-path

When a tunnel is not needed

Some providers ship local forwarding tools that avoid a public URL entirely:

Stripe CLI — forwards events directly to localhost:

stripe listen --forward-to localhost:3000/api/webhooks/stripe

The CLI prints a signing secret (whsec_...) for local verification. This is the fastest path for Stripe-only development.

GitHub — no official local forwarder. A tunnel is usually simpler than proxy hacks.

Use the provider CLI when you only need to verify handler logic. Use a tunnel when you need the exact URL format your production deployment will use.

Tips for reliable webhook testing

Webhook handler checklist

Before registering a URL, confirm your handler:

  1. Accepts POST requests on the registered path
  2. Reads the raw body (required for signature verification)
  3. Returns 2xx quickly (providers retry on failure)
  4. Validates signatures using the provider's documented method
  5. Is idempotent (providers may deliver the same event more than once)

Troubleshooting

SymptomCauseFix
Provider shows delivery failureHandler returned 4xx/5xx or timed outCheck local logs; return 200 after queuing work
Signature verification failsBody parsed before verificationUse raw body middleware; verify before JSON parse
No events arriveWrong URL or expired tunnelConfirm subdomain matches; restart if session expired
Request blocked by tunnelSession or usage limit may applyRestart tunnel; reduce test volume
Events arrive but handler silentWrong portUse --port to match your dev server

Free tier limits relevant to webhooks

LimitImpact
2-hour sessionRestart tunnel for long test sessions
1 GB bandwidthPlenty for webhook payloads
10 req/sNormal webhook volume is fine
Random subdomainUpdate provider URL on each new session
No request replayUse provider dashboards to resend events

FAQ

Do webhooks hit the browser warning page?
Webhook POSTs are server-to-server. Some automated clients may reach your app differently than a first-time browser visit in a browser.

Can I test multiple providers at once?
One tunnel per IP on the free tier. Route multiple paths on the same tunnel hostname (for example api/webhooks/stripe and api/github/webhook on your assigned subdomain).

What if my subdomain changes?
Update the webhook URL in each provider dashboard. There is no persistent URL on the free tier.

Should I use ngrok instead?
If you need a visual request inspector and one-click replay, ngrok is better. For quick anonymous testing, LocalToLink works without account signup. See LocalToLink vs ngrok.

For tunnel basics, see Expose Localhost to the Internet.

Try it now

Start a tunnel from your project directory — no account required.

$ npx --yes localtolink@latest

See the full CLI reference for flags and exit codes.

LocalToLink CLI 1.0.1 — verified 2026-09-20