Contents

Rate limiting restricts how many requests a client can make per unit of time. It protects an API from overload, password guessing, scraping and buggy third-party integrations that accidentally send thousands of requests a second. Limits are keyed by user, API key or IP address, and when exceeded the server responds with 429.

Here is why limits matter, which algorithms exist, what values to set and how to tell clients they have hit the limit.

Why limit request rates?

Rate limits stop one client from taking every server resource and hurting everyone else. Without them, a single looping partner script or a bot guessing passwords is enough to slow the site for all users.

What limits protect against:

  • password and code guessing — an attacker cannot try thousands of options;
  • scraping — competitors cannot download your catalogue in a minute;
  • spam — sign-ups, contact forms and SMS sending are capped;
  • integration bugs — an infinite loop in someone else's code will not take your server down;
  • expensive operations — report generation and calls to paid APIs stay under control.

For other vulnerabilities, see OWASP Top 10 explained.

What rate limiting algorithms are there?

The main algorithms are fixed window, sliding window and token bucket. They differ in how they behave at interval boundaries and whether they allow short bursts.

Algorithm How it works Pros Cons
Fixed window A counter resets every minute Simple, cheap Double burst at window edges
Sliding window Counts requests over the last N seconds More accurate Slightly more memory
Token bucket Tokens refill at a constant rate Allows short bursts Harder to explain to clients

Counters are usually kept in Redis: operations are atomic, fast and shared by all application servers. See Redis in a web project.

Heavy traffic on a highway Photo: Unsplash

What limits should different operations get?

Set limits per operation type: catalogue reads can be nearly unlimited, while sign-in, sign-up and code sending are strictly limited. Choose the limit key by meaning: user or API key for authenticated clients, IP address for anonymous ones.

RateLimiter::for('login', function (Request $request) {
    return [
        Limit::perMinute(5)->by($request->input('email')),
        Limit::perMinute(20)->by($request->ip()),
    ];
});

RateLimiter::for('api', function (Request $request) {
    return $request->user()
        ? Limit::perMinute($request->user()->plan->rate_limit)->by($request->user()->id)
        : Limit::perMinute(30)->by($request->ip());
});

Starting points:

  1. Sign-in and password reset — a few attempts per minute per account plus a separate per-IP limit.
  2. SMS and email sending — one code per minute and a small daily cap per number.
  3. Public API — a limit per key and plan, clear and documented.
  4. Heavy operations — exports and reports through a queue with a cap on concurrent jobs.

How do you tell a client they have exceeded the limit?

Respond with 429 Too Many Requests and headers that tell the client when it can retry. A well-designed client reads these headers and slows down by itself instead of hammering the server with retries.

HTTP/1.1 429 Too Many Requests
Retry-After: 30
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30

Document your limits in the API docs — we covered how in API documentation with OpenAPI. Clients that retry need idempotency — see idempotent payments and webhooks.

What mistakes happen when introducing limits?

The most common mistake is limiting only by IP: a whole office or mobile carrier can sit behind one address, and honest users start getting rejected. The second is switching blocking on immediately without looking at real traffic.

  • IP-only limits for authenticated users;
  • the same limit for reads and expensive operations;
  • no exemptions for your own services and monitoring;
  • counters in one server's memory when there are several servers;
  • responding with 500 or 403 instead of 429, leaving the client confused.

In short

  • Rate limiting protects against overload, guessing, scraping and integration bugs.
  • Algorithms: fixed window, sliding window, token bucket; counters live in Redis.
  • Limits vary by operation: strict for sign-in and SMS, lenient for reads.
  • Key limits by user or API key, and by IP for anonymous traffic.
  • When exceeded, return 429 with headers that say when to retry.

FAQ

  • Does rate limiting protect against DDoS?

    Only against small attacks and abuse. Serious DDoS protection happens at the network and CDN level, with dedicated traffic filtering services stopping requests before they reach the application.

  • How do you choose actual limit values?

    Look at real traffic: how many requests the most active honest user makes, and set the limit several times higher. Start in a log-only mode, then switch on blocking.

  • Where is it better to limit requests — in the app or at the load balancer?

    Both. The load balancer or CDN cuts crude floods by IP, while the application applies precise limits by user, plan and operation type.