The Chat Trigger webhook is a trigger primitive, not a product surface
Something I keep seeing: someone builds a chat workflow, grabs the Chat Trigger's public webhook URL, and pastes it straight into a customer-facing site. It works, so it ships. But that bare URL is now your entire security model.
Things the raw webhook doesn't do for you:
No caller identity. You can't tell one customer's traffic from another's, or either from a bot.
No rate limiting. If the workflow calls an LLM, every request costs you money. Someone running curl in a loop against your webhook is spending your API budget, not theirs.
No origin control. The URL works from any site on earth, and URLs that ship in client-side code always leak eventually. Once it leaks you can't un-leak it without breaking every integration.
No conversation history you can show a user next week or debug against.
To be clear, none of this is n8n's fault. The webhook is a trigger primitive and it's great at that. The mistake is treating a primitive like a product surface.
What I ended up doing is one hop of indirection: browser widget -> small gateway API -> the n8n webhook, which stays server-side and secret. The widget only ever sees the gateway URL plus a public site key. The gateway looks up the tenant by site key, checks the Origin header against domains that tenant registered, rate limits per tenant and per IP, writes both sides of the conversation to a table, then proxies server-to-server.
The site key + origin allowlist combo is the same trust model Stripe uses for publishable keys. It's not secret-based auth, it's "public identifier, verified context". For a widget that has to run in untrusted browsers I think that's the honest option, since anything stronger requires the customer's site to run server code, which kills the copy-paste embed.
Trade-offs I ran into: the extra hop adds latency, you have to handle webhook timeouts yourself instead of letting n8n's hosted chat page deal with it, and streaming responses through the proxy is noticeably more annoying than terminating them directly.
Curious how others handle this. Is everyone just shipping the bare webhook, or do you put something in front of it?