Rate limiting a chatbot widget without ruining UX
Chatbot widgets get abused — bots, scrapers, malicious keys. Here's how we rate limit without breaking legitimate visitors.
Every chatbot widget in production gets abused eventually. Someone finds the public embed key, scripts it, and spins up 10,000 queries an hour trying to exhaust your quota. Or a legitimate site accidentally embeds twice and doubles its traffic.
Here’s how we handle rate limiting in Anserra without breaking legitimate visitors.
What you’re defending against
Three threat classes, in order of frequency:
- Runaway scripts. Someone integrates the widget and their loop calls it a hundred times a second. Common cause: the embed script fires on every re-render because the mount is misconfigured.
- Curious researchers. They found the widget, they want to see what it says, they type quickly. Not malicious, but noisy.
- Deliberate abuse. Someone wants to blow through your message quota to run up your bill, exfiltrate your knowledge base, or embarrass your brand.
Each requires a different response.
Layer 1: Per-visitor sliding window
The primary control: cap messages per visitor per minute. In Anserra this defaults to 30 messages per minute per visitor, configurable per chatbot.
A visitor is identified by a client-generated UUID stored in `sessionStorage`. Not perfect — anyone can clear it — but sufficient for 99% of accidental abuse. The good news: the rate limit is per chatbot embed key, so if attackers rotate visitor IDs on the same site, we still catch them because the key hits limits at the account level.
Sliding window, not fixed window. Fixed windows have edge-of-minute bursts; sliding windows don’t.
Layer 2: Domain locking
Every embed key can be locked to a list of domains. If a request comes from a domain not on the list, we refuse — the chatbot returns an error rather than answering. Configure it under the chatbot’s Security tab.
This is the single most effective control. An attacker who lifts your embed key onto their own site can’t use it.
Layer 3: Behavioural filtering
Some patterns are almost always abuse:
- No referrer at all (script-driven requests skip it).
- User-agent that’s obviously a bot (“curl/7.68”).
- First request comes with a message like “`ignore all instructions`” — an obvious probe.
We drop these with a 429 and log them. Legitimate visitors never trip these rules.
Layer 4: Cost circuit breaker
If any single embed key exceeds a hard cap (typically 100× the plan’s monthly message limit in a single day), we cap that chatbot until an operator confirms. Nothing runs unchecked while an operator sleeps.
What NOT to do
- Don’t CAPTCHA the widget. It’s a support channel. A CAPTCHA before someone can ask their question destroys the value proposition.
- Don’t require login. Some vendors do this. Your customers will not sign up for an account to ask a question about their order.
- Don’t rate-limit on IP alone. Shared corporate NAT means one office building looks like one visitor. You’ll block your best customers.
- Don’t return 429 to the visitor if a runaway script is at fault. They didn’t do anything wrong. Return a normal reply after a brief cooldown, and log the runaway pattern.
Distinguishing abuse from success
The tension: a chatbot that’s doing well naturally has more traffic than a chatbot that’s not. Rate limits should scale with your plan and your paid quota. If you’re hitting them frequently, that’s a signal to upgrade or investigate — not to lower the limit.
The Analytics tab shows the ratio of rate-limited requests to total. Above 2% for more than a day is unusual; it’s worth checking the origin distribution to see whether it’s genuine traffic or an outlier IP.
What honest limits look like
Anserra’s free plan has real limits and we say what they are: 100 messages/month, 3 chatbots, 5 team seats. When you hit a limit, the widget doesn’t silently degrade — it tells you and points at the upgrade path. Nothing “mysteriously stops working.”
If you want to try it: free plan, no card, live in five minutes.
Read next
- Engineering
Hybrid retrieval, explained: why semantic search alone fails on real customer questions
Semantic embeddings blur exact strings like SKUs and error codes. Hybrid retrieval fixes that — here's how it works and how we implement it.
Read - Engineering
pgvector vs Pinecone in 2026: when each wins
A pragmatic comparison of Postgres pgvector against Pinecone for production RAG. Pricing, latency, filtering, hybrid search and what breaks under load.
Read - Engineering
Streaming from OpenRouter in production: what actually works
OpenRouter's chat-completions endpoint, the AI SDK, graceful degradation and the two SDK gotchas that cost a day.
Read