Find Any Webhook Event in Under 50ms — No Regex, No Exact Match Required
The standard interface for searching webhook logs is a text field that does substring matching. Type cus_123456 and find events containing that string. Type checkout.session and find events of that type. It is functional in the same way that a card catalog is functional — technically correct, deeply inadequate when you are under pressure and you do not know exactly what you are looking for.
Real incidents do not give you exact strings. A customer says "I upgraded two hours ago." You do not have their customer ID memorized. You do not remember the exact Stripe event type for a subscription upgrade. You know what happened, conceptually, and you need to find the event that represents it.
HookTunnel's semantic search lets you describe what you are looking for in plain English. The system finds events by what they mean — not just whether they contain the characters you typed. Results arrive in under 50 milliseconds. No server call. No rate limit. Entirely in your browser.
The 11pm Support Ticket
It is 11:17pm. A customer email landed in your inbox at 10:58pm: "I upgraded to Pro two hours ago and I still can't access Pro features. My invoice shows the charge went through."
You are not on call. You checked your email out of habit. Now you are in it.
You open HookTunnel. Today has 400 webhook events. You do not know this customer's Stripe customer ID off the top of your head. You do not know the exact event type that Stripe fires for a subscription upgrade — is it customer.subscription.updated? customer.subscription.created? Both? You are tired. You do not want to write a regex.
You type: "customer upgrade"
Forty milliseconds.
One result surfaced at the top: a customer.subscription.updated event from 8:54pm. The payload shows the customer's email — it matches. The plan field changed from free to pro. The event was delivered. Your handler returned 200. But there is no confirmation receipt.
The outcome state shows: Applied Unknown.
You click into the event. The timeline shows delivery at 8:54pm, handler response at 8:54:01pm (200 OK), SLA timer elapsed at 8:55:01pm, alert triggered — and no one responded because you had PagerDuty misconfigured for that hook. The handler processed the delivery and swallowed an exception. You can see it in the payload inspector: the plan.nickname field is pro_annual but your handler was checking for pro — a string mismatch you introduced in last week's pricing update.
You fix the bug (one line in the handler). You replay the event. Receipt arrives in eight seconds: Applied Confirmed. You send the customer a reply: "I found the issue and fixed it. Try accessing Pro features now — it should work." You copy them on a $10 credit for the trouble.
It is 11:34pm. Seventeen minutes from email to resolution. The customer replies at 11:36pm: "It's working! Thank you."
You close your laptop.
This is not a story about fast search. Fast search is the mechanism. The story is about being able to prove what happened — to yourself, to the customer, to your team — without reconstructing it from memory and log files and intuition. The search found the event. The outcome state told you it did not apply. The timeline told you why. The fix was obvious. The resolution was clean.
The anxiety of not knowing — "did this even land, did it work, is there a bug, which event is it?" — collapsed into clarity in under a minute. That emotional shift is the product.
How It Works
WASM Embeddings in the Browser
When you load HookTunnel's dashboard, a small WASM module loads alongside it. That module contains a 384-dimensional sentence embedding model — a neural network that converts text into a vector of numbers representing semantic meaning. The model runs entirely in your browser. No API call is made when you search. No payload leaves your machine.
When events are displayed in the inspector, their payload contents are embedded locally: the event type, key fields from the JSON body (customer email, amount, status fields, description strings), and any headers of significance. These vectors are stored in memory for the duration of your session.
When you type a query, your query is embedded with the same model. The system computes cosine similarity between your query vector and every event vector in the current view. Results are ranked by similarity score and returned in under 50 milliseconds for typical session sizes (up to 2,000 events in memory).
Why 384 Dimensions
The embedding model used is a distilled version of a sentence transformer optimized for short text similarity. 384 dimensions is the sweet spot for browser-executable models: high enough to capture semantic relationships between domain-specific terms ("upgrade", "subscription change", "plan updated" all map to nearby vectors), small enough to run in under 5ms per embedding on commodity hardware.
The model understands that "customer upgrade" and customer.subscription.updated are related. It understands that "payment failed" and invoice.payment_failure are related. It understands that "Twilio call not delivered" and call.status.no-answer are related. Keyword search does not understand any of this. It matches characters.
Why Client-Side
This architecture is the only one that can satisfy all three constraints simultaneously: speed under 50ms, no payload egress, and no rate limiting.
Server-side semantic search requires an API round-trip (minimum 80-150ms on a fast connection), requires sending your payload data to an external service, and is subject to rate limiting under load. Browser-side semantic search is instant, private, and unconstrained.
There is also an operational benefit: semantic search works when you are offline or on a flaky connection. Event payloads are already in your browser. The embedding model is already in your browser. Search is local computation.
What Gets Indexed
The embedding includes:
- Event type (
customer.subscription.updated,invoice.payment_succeeded, etc.) - String values from the JSON payload up to three levels deep
- HTTP headers with semantic content (Content-Type, User-Agent patterns)
- Outcome state labels (Applied Confirmed, Applied Unknown, Applied Failed)
- Timestamp context (relative: "2 hours ago", "this morning")
Numeric values, UUIDs, and raw binary data are excluded from embedding — they contain no semantic content useful for natural language search.
The Similar Requests Panel
Semantic search surfaces individual events. The Similar Requests panel surfaces patterns.
When you open any event in the inspector, HookTunnel computes its similarity to every other event in your history and surfaces the top 10 most similar. These are not events of the same type — they are events with similar semantic content. A customer.subscription.updated for a plan change might surface alongside a checkout.session.completed for the same customer if both payloads contain overlapping customer context.
The pattern question this answers is: "Is this event a one-off or part of a cluster?"
If you are investigating a failed event and the Similar Requests panel shows 15 other events with similar failure characteristics from the same two-hour window, you know you are looking at an incident, not an anomaly. If the panel shows nothing similar, you are likely looking at a customer-specific edge case.
This changes how you triage. A one-off gets a targeted fix. A cluster gets a blameless postmortem and a systematic solution.
No Competitor Has This
Every webhook inspection tool available today — RequestBin, webhook.site, Ngrok's dashboard, Svix, Hookdeck — uses keyword or exact-match search. You must know what you are looking for before you can find it.
This is a fundamental limitation of the architecture, not a gap in effort. Building server-side semantic search requires sending payloads to an API and waiting for results. Building client-side semantic search requires shipping a WASM embedding model and engineering around browser constraints.
The result is that every competitor has the same search interface: a text field, a type filter, and a date range. When you do not know the exact string, you scroll. When you have 400 events and you are tired and the customer is waiting, you scroll through 400 entries hoping you recognize the right one.
HookTunnel does not make you scroll. You describe what you are looking for. The system finds it.
FAQ
What if my payloads contain sensitive data? Does it leave my browser?
No. The embedding model runs entirely in your browser via WASM. Your payload data is never sent to HookTunnel's servers for search purposes — it is only stored in server-side storage as you configured (encrypted at rest, with field-level redaction available). The semantic search computation happens locally on your machine using data already loaded into the browser session.
Does it work offline?
Yes. If you have previously loaded events into the inspector, semantic search works without a network connection. The WASM model is cached after first load (about 8MB). Subsequent sessions load from cache and are functional offline for events already in memory.
Does it search headers as well as body?
Yes. Headers with semantic content are included in the embedding. HTTP method, Content-Type, and any custom headers your provider sends (Stripe's Stripe-Event-ID, GitHub's X-GitHub-Event, Twilio's signature header) are all embedded and searchable. Searching "stripe payment" will surface events from Stripe's delivery headers even if the payload content is minimal.
How accurate is it for domain-specific terms?
The model is trained on general text corpora and generalizes well to API vocabulary. Stripe event type names, HTTP status descriptions, and common webhook payload field names ("customer", "subscription", "amount", "status", "invoice") are all within the model's semantic space. Very domain-specific abbreviations or internal naming conventions may not surface correctly — if your company calls subscription upgrades "tier elevations" internally, a search for "subscription upgrade" may not find events where "tier elevation" appears in a metadata field. The search works best when you use language similar to what the payload contains.
What is the maximum session size for semantic search?
The current implementation handles up to 5,000 events in memory with sub-50ms response times on modern hardware. Beyond 5,000 events, results are computed against the most recent 5,000 loaded. For larger searches across historical data, use the date range filter to narrow the window before searching, or use the structured filter (event type, outcome state) to reduce the set first.
Does it search across all my hooks or just the current one?
By default, search operates on the events currently loaded in the inspector view. If you have a single hook selected, it searches that hook's events. If you are in the "All Hooks" view, it searches across all hooks' events loaded in the current session. Cross-hook semantic search is bounded by the 5,000-event session limit and is most useful for cross-cutting investigations ("find all payment-related events in the last hour across all hooks").
Search your webhook history semantically
Find any event in under 50ms. No regex, no exact match required.
Get started free →