Examples
See Universal Rate Limiter in action with real code examples
Live Playground
Try the rate limiter yourself! Click the button below to test a limiter that allows 3 requests per 10 seconds.
Configuration
Max Requests:3
Time Window:10 seconds
Storage:MemoryStorage
Console Output
Click "Test Request" to see output...
Simple API Rate Limiting
Basic rate limiting for API endpoints with a fixed limit per time window.
simple-api-limiting.ts
1import { createRateLimiter, MemoryStorage } from 'universal-rate-limiter';
2
3const apiLimiter = createRateLimiter({
4 key: 'api-endpoint',
5 max: 100,
6 window: '15m',
7 storage: new MemoryStorage()
8});
9
10// In your API handler
11async function handleRequest(req, res) {
12 const result = await apiLimiter.check();
13
14 if (!result.allowed) {
15 return res.status(429).json({
16 error: 'Too many requests',
17 retryAfter: result.retryAfter
18 });
19 }
20
21 // Process request
22 res.json({ data: 'Success', remaining: result.remaining });
23}Per-User Rate Limiting
Dynamic rate limiting based on user ID or IP address.
per-user-limiting.ts
1import { createRateLimiter, MemoryStorage } from 'universal-rate-limiter';
2
3const userLimiter = createRateLimiter({
4 key: (req) => `user-${req.userId || req.ip}`,
5 max: 50,
6 window: '1h',
7 storage: new MemoryStorage()
8});
9
10// In your Express app
11app.use(async (req, res, next) => {
12 const result = await userLimiter.check(req);
13
14 if (!result.allowed) {
15 return res.status(429).json({
16 error: 'Too many requests from this user',
17 retryAfter: result.retryAfter
18 });
19 }
20
21 // Add rate limit info to response headers
22 res.setHeader('X-RateLimit-Limit', '50');
23 res.setHeader('X-RateLimit-Remaining', result.remaining.toString());
24
25 next();
26});Express: Global + Route-Specific Limits
Combine global rate limiting with stricter limits for specific sensitive routes.
express-multi-tier.ts
1import express from 'express';
2import { rateLimitExpress } from 'universal-rate-limiter';
3
4const app = express();
5
6// Global rate limit: 1000 requests per hour
7app.use(rateLimitExpress({
8 key: (req) => `global-${req.ip}`,
9 max: 1000,
10 window: '1h'
11}));
12
13// Stricter limit for login endpoint: 5 attempts per 15 minutes
14app.post('/api/auth/login',
15 rateLimitExpress({
16 key: (req) => `login-${req.ip}`,
17 max: 5,
18 window: '15m'
19 }),
20 (req, res) => {
21 // Handle login
22 }
23);
24
25// Stricter limit for registration: 3 per day
26app.post('/api/auth/register',
27 rateLimitExpress({
28 key: (req) => `register-${req.ip}`,
29 max: 3,
30 window: '1d'
31 }),
32 (req, res) => {
33 // Handle registration
34 }
35);Next.js API Routes
Rate limiting in Next.js API routes with proper error handling.
app/api/data/route.ts
1import { NextRequest, NextResponse } from 'next/server';
2import { createRateLimiter, MemoryStorage } from 'universal-rate-limiter';
3
4const limiter = createRateLimiter({
5 key: (req: NextRequest) => req.ip ?? 'anonymous',
6 max: 10,
7 window: '1m',
8 storage: new MemoryStorage()
9});
10
11export async function GET(request: NextRequest) {
12 const result = await limiter.check(request);
13
14 if (!result.allowed) {
15 return NextResponse.json(
16 {
17 error: 'Too many requests',
18 retryAfter: Math.ceil(result.retryAfter / 1000) // Convert to seconds
19 },
20 {
21 status: 429,
22 headers: {
23 'Retry-After': Math.ceil(result.retryAfter / 1000).toString()
24 }
25 }
26 );
27 }
28
29 // Process request
30 return NextResponse.json({
31 message: 'Success',
32 rateLimit: {
33 remaining: result.remaining,
34 limit: 10
35 }
36 });
37}React Hook in Client Component
Limit user actions on the client side, like button clicks or form submissions.
ContactForm.tsx
1'use client';
2
3import { useState } from 'react';
4import { useRateLimit } from 'universal-rate-limiter';
5
6export function ContactForm() {
7 const [status, setStatus] = useState('');
8 const { allowed, remaining, attempt } = useRateLimit('contact-form', {
9 max: 3,
10 window: '1h'
11 });
12
13 const handleSubmit = async (e: React.FormEvent) => {
14 e.preventDefault();
15
16 if (!allowed) {
17 setStatus(`Too many submissions. You have ${remaining} remaining.`);
18 return;
19 }
20
21 await attempt();
22
23 // Submit form
24 try {
25 await fetch('/api/contact', {
26 method: 'POST',
27 body: JSON.stringify({ /* form data */ })
28 });
29 setStatus(`Form submitted! ${remaining - 1} submissions remaining.`);
30 } catch (error) {
31 setStatus('Error submitting form');
32 }
33 };
34
35 return (
36 <form onSubmit={handleSubmit}>
37 <input type="email" required />
38 <textarea required />
39 <button type="submit" disabled={!allowed}>
40 Submit ({remaining} remaining)
41 </button>
42 {status && <p>{status}</p>}
43 </form>
44 );
45}Multiple Time Windows
Combine multiple rate limiters for different time windows (e.g., per second, per minute, per hour).
multi-window-limiting.ts
1import { createRateLimiter, MemoryStorage } from 'universal-rate-limiter';
2
3// Create multiple limiters for different time windows
4const perSecondLimiter = createRateLimiter({
5 key: (req) => `second-${req.ip}`,
6 max: 10,
7 window: '1s',
8 storage: new MemoryStorage()
9});
10
11const perMinuteLimiter = createRateLimiter({
12 key: (req) => `minute-${req.ip}`,
13 max: 100,
14 window: '1m',
15 storage: new MemoryStorage()
16});
17
18const perHourLimiter = createRateLimiter({
19 key: (req) => `hour-${req.ip}`,
20 max: 1000,
21 window: '1h',
22 storage: new MemoryStorage()
23});
24
25// Middleware to check all limiters
26async function rateLimitMiddleware(req, res, next) {
27 const limiters = [
28 { limiter: perSecondLimiter, name: 'per second' },
29 { limiter: perMinuteLimiter, name: 'per minute' },
30 { limiter: perHourLimiter, name: 'per hour' }
31 ];
32
33 for (const { limiter, name } of limiters) {
34 const result = await limiter.check(req);
35 if (!result.allowed) {
36 return res.status(429).json({
37 error: `Rate limit exceeded (${name})`,
38 retryAfter: result.retryAfter
39 });
40 }
41 }
42
43 next();
44}Custom Error Response
Customize the response when rate limits are exceeded.
custom-error.ts
1import { rateLimitExpress } from 'universal-rate-limiter';
2
3const customRateLimiter = rateLimitExpress({
4 key: (req) => `api-${req.ip}`,
5 max: 100,
6 window: '15m',
7 onRateLimit: (req, res, result) => {
8 res.status(429).json({
9 error: {
10 code: 'RATE_LIMIT_EXCEEDED',
11 message: 'You have exceeded the rate limit',
12 details: {
13 limit: 100,
14 window: '15 minutes',
15 retryAfter: Math.ceil(result.retryAfter / 1000),
16 ip: req.ip
17 }
18 }
19 });
20 }
21});
22
23app.use('/api', customRateLimiter);