Using Ngrok’s Built‑In Request Inspector to Debug Webhooks Without Changing Code
Learn how to enable Ngrok’s inspection UI, view request details, replay calls, and manage the trade‑offs of local storage and overhead.
13 Feb 2026, 16:07 UTC

Problem: You need to see exactly what a webhook sends to your local service
When integrating a third‑party service (e.g., a payment gateway or chat platform) you often rely on webhooks. The payload may contain headers, query strings, or a JSON body that you must validate, but you cannot modify the provider’s code to add logging. Running a local copy of your service and exposing it with a tunnel is common, yet you still lack visibility into the raw request that arrives.
Thesis: Ngrok’s inspection UI gives you instant, code‑free visibility into every HTTP request and response flowing through the tunnel, plus a replay feature for iterative testing.
1. Enabling the inspector
Ngrok enables request inspection by default. If you have customized your ngrok.yml and want to be explicit, set:
inspect: true
web_addr: localhost:4040 # inspector UI address
Start the tunnel for your local service (here a Flask app on port 5000):
# Run in a terminal where ngrok is in your PATH
ngrok http 5000
Ngrok prints a forwarding URL, e.g. https://abcd1234.ngrok.io → http://localhost:5000. The inspector UI is available at http://127.0.0.1:4040/inspect/http.
2. Worked example: inspecting a GET request
With the tunnel running, send a request to the public URL, for example:
curl https://abcd1234.ngrok.io/api/webhook?foo=barOpen
http://127.0.0.1:4040/inspect/httpin a browser. You will see a list of captured requests; the latest entry shows:- Request method, URL, and headers
- Query string parameters
- Response status, headers, and body (if any)
- Timing information (latency, duration)
Click the request line to expand the full detail view. If you need to test the same payload again, use the “Replay” button in the UI. Ngrok will resend the exact request to your local Flask app, letting you verify changes without asking the provider to resend.
3. Trade‑offs and practical checks
Storing request data enables the UI but consumes memory (or disk if you enable persistence). For low‑to‑moderate traffic the overhead is negligible, but sustained high volume can increase RSS noticeably.
How to verify the overhead yourself:
- Run two tunnels in separate terminals:
ngrok http 5000 --inspect=truengrok http 5000 --inspect=false- With each tunnel active, generate a steady stream of requests (e.g.,
while true; do curl -s https://<subdomain>.ngrok.io/ping >/dev/null; done). - In another terminal, inspect memory usage:
ps -o pid,rss,command -C ngrok(Linux/macOS) or use Task Manager → Details on Windows. Compare the RSS values; the inspect‑enabled process will show a higher resident set size.
Security consideration: The inspection data is stored locally and is not encrypted. Anyone with access to the host machine can open http://127.0.0.1:4040 and view request bodies, potentially exposing tokens or passwords. Mitigation steps:
- Bind the inspector to localhost only (the default
web_addr: localhost:4040). - If you must expose the UI, protect it with basic auth via
ngrok.yml: auth: "user:pass"- Clear the inspection history when you’re done:
curl -X POST http://127.0.0.1:4040/api/inspect/http(requires no auth by default).
4. Actionable closing
For production‑like testing where you want to mimic real traffic without the inspector’s overhead, start Ngrok with --inspect=false. When you need to debug, toggle inspection on, use the UI to inspect and replay, then turn it off again or clear the history. This workflow lets you validate webhook contracts, API payloads, or SPA interactions without adding logging statements or external tools to your service.
Remember: the inspector is a local debugging aid. Always verify that any sensitive data you see in the UI is handled securely in your application, and never expose the inspector UI to untrusted networks.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.