Rate Limiting UX Considerations
Design FE for 429s: Retry-After, backoff, idempotency, and login lockouts without trapping users.
- security
- rate-limiting
- ux
- http
- 429
Rate limits protect APIs from abuse (credential stuffing, scraping, card testing). Frontend that ignores 429 and Retry-After retries blindly, multiplies load, and locks out real users. Security and UX meet at the error boundary.
Docs: MDN 429, RFC 6585, OWASP Credential Stuffing.
What the browser sees
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{"error":"rate_limited","message":"Try again in 30s"}
async function fetchWithLimit(input, init) {
const res = await fetch(input, init);
if (res.status !== 429) return res;
const retryAfter = Number(res.headers.get('Retry-After')) || 5;
// surface UI; do not tight-loop
throw Object.assign(new Error('rate limited'), { retryAfter });
}
UX patterns that help security
| Situation | UI | Avoid |
|---|---|---|
| Login stuffing lockout | Clear “too many attempts” + support path | “Invalid password” forever |
| Search API limit | Disable submit, countdown | Silent infinite spinner |
| Payment retries | Idempotency key + single flight | Double charge clicks |
| Background sync | Exponential backoff + jitter | Fixed 50ms retry |
function backoff(attempt) {
const base = Math.min(30_000, 500 * 2 ** attempt);
return base + Math.random() * 200;
}
Idempotency for mutations
await fetch('/api/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify(order),
});
Retries after timeouts must not create duplicate side effects — coordinate with backend support for keys.
Credential stuffing UX
- Progressive delays and CAPTCHA after N failures (server-driven).
- Don’t reveal whether email exists if product policy forbids it.
- MFA challenges on risk, not only on failure count.
- Show account recovery paths when locked.
Client-side “rate limits”
Debouncing search is UX, not security. Attackers call APIs directly. Still debounce to reduce accidental 429s for legit users.
Interview out-loud
“I handle 429 with Retry-After, backoff and jitter, and user-visible cooldowns. Mutations use idempotency keys. Login lockouts need clear messaging without helping attackers enumerate accounts. Client debouncing isn’t a security control.”
Reviewer prompts
- What is the asset (session, PII, money movement)?
- What is the attacker capability (web, XSS, network, dependency)?
- Which control fails closed if misconfigured?
- Is the server still enforcing authz?
- Any new third party, iframe, or URL sink?
Residual risk note
Browser controls reduce likelihood and impact; they do not eliminate bugs. Prefer defense in depth: safe defaults in code, strict headers, and monitoring (CSP reports, auth anomaly alerts). When product pressure weakens a control, write down the accepted risk and a revisit date.
Related
- Auth session UX security
- Frontend security threat model
- Browser DevTools Network panel
- CSRF basics for SPAs
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Auth Session UX SecuritySession UX that doesn’t weaken security: login states, logout everywhere, idle timeouts, and step-up auth.
- Clickjacking and X-Frame-OptionsStop UI redress attacks with frame-ancestors CSP and X-Frame-Options; know when embedding is intentional.
- Content Security Policy (CSP)Reduce XSS blast radius with CSP — script-src nonces/hashes, strict-dynamic, report-only rollout, and what CSP does not fix.
- CSRF Basics for SPAsCross-site request forgery against cookie sessions: SameSite, CSRF tokens, and SPA fetch patterns.
- Dependency Supply Chain Risknpm malware, lockfiles, pin policies, and practical frontend controls against dependency attacks.