HTTP 429 Too Many Requests is the status code a server returns when a client exceeds a rate limit for a given URL. This often happens when exhausting API quotas or when scraping public web pages too aggressively. The error doesn't necessarily say that requesting the resource isn't allowed, but rather points out that the server cannot handle more requests like that at the moment. Let's go and understand what this code means exactly and how to make it go away.

HTTP status codes

HTTP status codes tell clients what happened with the request they sent. They are grouped by their first digit into 5 categories. The group tells a client whether a request succeeded, requires another step, or failed:

Range Meaning Common examples
1xx Informational response while processing continues 100 Continue
2xx The request succeeded 200 OK, 201 Created, 204 No Content
3xx The client needs to follow a redirect or use cached content 301 Moved Permanently, 304 Not Modified
4xx The client must change something about the request or its behavior 400 Bad Request, 401 Unauthorized, 404 Not Found, 429 Too Many Requests
5xx The server failed to complete an otherwise valid request 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable

HTTP 429 belongs to the 4xx group because the client is expected to change its behavior by sending fewer requests or waiting before trying again. It does not necessarily mean the request data is malformed or that the server is broken.

A request can be valid and still receive a 429 because it arrived after the client's allowed quota had been exhausted.

HTTP 429: Too Many Requests

You might encounter this error while calling an API, scraping a website, submitting forms, polling for updates, or running several background jobs at once. The request may be perfectly valid. The problem is how frequently the requests are being sent.

A typical response looks like this:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60

{
  "error": "rate_limit_exceeded",
  "message": "Try again in 60 seconds"
}

The server is telling the client to slow down. Retrying the same request immediately usually extends the problem rather than fixing it.

HTTP 429 versus HTTP 503

Both status codes call for controlled retries. The distinction matters for monitoring as repeated 429 responses usually point to client behavior or plan limits, while widespread 503 responses usually indicate a server-side availability problem.

Here's the main difference between these two error status codes:

  • HTTP 429 means the client has exceeded a limit. The response is usually specific to an API key, account, IP address, or request pattern.
  • HTTP 503, known as Service Unavailable, generally means the service itself cannot handle the request because it is overloaded or undergoing maintenance.

Why servers return HTTP 429

Rate limits protect services from accidental overload, abusive traffic, and unexpectedly expensive workloads. They also help providers distribute limited capacity fairly among users.

Common causes include:

  • Sending too many requests per second or minute
  • Running more concurrent requests than an API plan permits
  • Sharing one API key across too many workers
  • Polling an endpoint more frequently than necessary
  • Retrying failed requests immediately and without a limit
  • Scraping pages faster than a website can reasonably serve them
  • Exceeding a daily or monthly account quota

Not every limit is based on an IP address. A service may limit requests by API key, account, endpoint, user, geographic region, or a combination of these factors.

Check the Retry-After header

A 429 response may include a Retry-After header telling the client when it can try again. The value can be a number of seconds:

Retry-After: 60

But it can also be an HTTP date:

Retry-After: Wed, 26 Aug 2026 14:30:00 GMT

Clients should support both formats when possible.

Some APIs also return headers describing the active limit, remaining requests, and reset time. Header names vary between providers, so check the API documentation instead of assuming one universal format.

A 503 response may also contain Retry-After, but reducing one client's request rate might not resolve the underlying outage.

How clients should handle HTTP 429

The correct response to receiving the Too Many Requests status code is to reduce pressure on the server immediately and be more mindful in the future.

Respect Retry-After

Do not retry before the server's requested delay has passed. If several workers receive a 429 together, add a small random delay so they do not all retry at exactly the same moment.

Use exponential backoff and jitter

When Retry-After is not specified, increase the delay after every failure. If that doesn't help, increase it again exponentially. You can also consider adding jitter which adds randomness to each delay. This prevents synchronized clients from creating another traffic spike when the waiting period ends.

Limit retries

A retry loop must have a maximum number of attempts. Permanent account quotas, invalid plans, and strict website limits will not be fixed by retrying forever.

Reduce concurrency

A scraper with many workers can exceed a limit even when each worker appears slow. Use a shared rate limiter or queue so all processes follow the same request budget.

Cache and batch requests

Avoid requesting the same resource repeatedly. Cache responses when freshness requirements allow it, combine requests when an API supports batching, and stop polling when the result is no longer needed.

Authenticate correctly

Anonymous requests often have lower limits than authenticated ones. Confirm that the API key is present, belongs to the expected account, and is not being shared unintentionally across environments.

Retrying a 429 response

Here's a simplified Ruby example that respects a numeric Retry-After value and otherwise falls back to exponential backoff with jitter:

require "faraday"

MAX_RETRIES = 5
attempt = 0

loop do
  response = Faraday.get("https://api.example.com/data")
  break unless response.status == 429

  raise "Rate limit exceeded" if attempt >= MAX_RETRIES

  retry_after = Integer(response.headers["retry-after"], exception: false)
  backoff = [2**attempt, 60].min
  delay = retry_after || backoff

  sleep(delay + rand)
  attempt += 1
end

A production implementation should also handle an HTTP-date Retry-After value, request timeouts, network errors, logging, cancellation, and the API's documented rate-limit headers.

Conclusion

If you are getting HTTP error 429 when using an external API or when scraping public web sites, it's important to stop the requests immediately and retry later. How much later can be determined from the Retry-After header if present. If the header is not present, try exponential backoff with jitter to not overwhelm the servers on the other side.