Blog

429 Too Many Requests: what it means and how to fix it

Kevin Wang
Kevin Wang
Founder, AnyAPI · October 28, 2026
httprate-limitsapireddithow-to
429 Too Many Requests: what it means and how to fix it
Key findings
  • Seeing it on a website? Wait a few minutes and stop refreshing. The site thinks too many requests came from you, and every refresh is one more.
  • In code, wait exactly as long as Retry-After says, and when it's missing, back off exponentially with random jitter.
  • Two of three free APIs refused with a 403 instead of a 429. GitHub's unauthenticated API served 60 requests in an hour, then said "API rate limit exceeded" with a 403. Reddit's public JSON returned a 403 block page on the first request. Only CoinGecko's keyless API sent a real 429: after 5 requests, with Retry-After: 60.
  • 100 Reddit subreddit reads through AnyAPI's Subreddit Posts endpoint all came back 200, one after another, in under four minutes.

Built on AnyAPI

470 scraping and data APIs behind one key.

Every endpoint in this post is one call away. Pay per request in USD from a prepaid wallet, with automatic failover when a provider breaks. No subscription, no card to start.

Get ~160 free requests$0.10 of credit on signup.

You refreshed a page a few times, or your script ran a loop a little faster than the server liked, and now the page just says "429 Too Many Requests". Nothing is broken on your side. The server counts requests from you, usually by IP address or account, and you went over its count for now.

I went looking for real limits on October 2, 2026. From one home internet connection, I sent polite, one-at-a-time requests to three free APIs (Reddit, GitHub, and CoinGecko) until each one refused, and saved every header. Then I ran 100 Reddit reads through a paid endpoint to see what the same job looks like with an API key.

Reddit public JSON (403): 00Reddit public JSON (403)CoinGecko, no key (429): 55CoinGecko, no key (429)GitHub, no token (403): 6060GitHub, no token (403)
Requests each free API served before refusing, from one home IP on October 2, 2026, one request a second. The code in brackets is what the refusal used. GitHub's count is its own x-ratelimit-used header.

If you saw this error on a website

You don't need to fix anything in your browser. Try these, in order:

  1. Wait a few minutes, then reload once. A rate limit clears on its own when its window ends. The two measured here lasted a minute and an hour.
  2. Don't keep refreshing. On many services every request counts, refused ones included. CoinGecko's docs say so directly.
  3. Turn off your VPN or try another network. Limits are often counted per IP address. GitHub's docs say unauthenticated requests are "associated with the originating IP address", and CoinGecko's keyless limit is "shared across all users on the same IP". A VPN, an office, or a school network can put you over before you've done much.
  4. Sign in, if the site has accounts. Services like GitHub and Reddit give signed-in users their own, larger limit.
  5. If it never clears, the site may have blocked you instead. Contact the site.

The rest of this page is for developers.

At a glance

QuestionWhat the data says
What does 429 mean?Too many requests in a given amount of time (RFC 6585, section 4)
How long do I wait?Whatever Retry-After says: 60 seconds on CoinGecko's 429
Does every API use 429?No. GitHub and Reddit both refused with 403
What's GitHub's free limit?60 requests an hour per IP; the 61st got a 403 and a 58-minute wait
What's Reddit's free limit?None without OAuth: the first request got a 403 block page
Does retrying early help?No. CoinGecko's early retry got another 429 with Retry-After: 48

A 429 asks you to wait, and Retry-After says how long

The status code comes from RFC 6585, which defines it as "the user has sent too many requests in a given amount of time". The response "MAY include a Retry-After header indicating how long to wait before making a new request".

Retry-After comes in two forms, per MDN: a number of seconds (Retry-After: 60) or an HTTP date (Retry-After: Fri, 02 Oct 2026 22:17:35 GMT). Your code has to handle both.

The RFC also says servers don't have to use 429 at all. Section 7.2 notes that "servers are not required to use the 429 status code" and may "just drop connections, or take other steps". Two of the three APIs below did exactly that.

Only one of three free APIs sent an actual 429

All three tests ran from the same connection, with a User-Agent that named this study and gave a contact address. CoinGecko and GitHub got one request a second until the first refusal.

CoinGecko: a textbook 429 after 5 requests

CoinGecko's price API works without a key. Its rate limit docs don't give a number for keyless use, only "IP-based rate limiting".

CoinGecko's Errors and Rate Limits page: Paid plans, rate limit depends on your plan. Demo plan, 100 calls per minute. Keyless, IP-based rate limiting shared across all users on the same IP. A warning that all requests count toward the per-minute limit, including 4xx and 5xx errors
CoinGecko's docs on October 2, 2026: the keyless limit has no published number, and refused requests count too.

Five requests went through. The sixth got this, at 22:16:35 UTC:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Server: cloudflare

{"status":{"error_code":429,"error_message":"You've exceeded the Rate Limit. Please visit https://www.coingecko.com/en/api/pricing to subscribe to our API plans for higher rate limits."}}

One request went out early, 12 seconds later. It got another 429 with Retry-After: 48, so the clock had kept running from the first refusal and the early try bought nothing. A request sent after the 60 seconds were up came back 200.

GitHub: 60 an hour, then a 403

GitHub's rate limit docs say "the primary rate limit for unauthenticated requests is 60 requests per hour", counted per IP address.

GitHub Docs, Rate limits for the REST API: unauthenticated requests are associated with the originating IP address, and the primary rate limit for unauthenticated requests is 60 requests per hour; authenticated users get 5,000 requests per hour
GitHub's REST API docs on October 2, 2026: 60 requests an hour without a token, 5,000 with one.

Every response carried a countdown: x-ratelimit-limit: 60, x-ratelimit-remaining, and x-ratelimit-reset. When x-ratelimit-used reached 60, the next request got this:

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Used: 60
X-RateLimit-Resource: core
X-RateLimit-Reset: 1790982853

{"message":"API rate limit exceeded for <your IP>. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)","documentation_url":"https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"}

There's no Retry-After here. X-RateLimit-Reset is a Unix timestamp, 23:14:13 UTC, exactly one hour after the first request that counter saw. So the hour starts at your first request, not on the clock hour, and this refusal at 22:16:13 meant a 58-minute wait. At 23:14:29, a request came back 200 with 59 remaining and a new reset exactly an hour later.

GitHub's docs say an exceeded limit gets "a 403 or 429 response", and that you "should not retry your request until after the time specified by the x-ratelimit-reset header". If your code only checks for 429, it'll miss this one.

Reddit: a 403 block before any limit

Adding .json to a Reddit URL, as in reddit.com/r/programming/hot.json, looks like the no-key way to read Reddit from a script. The first request got a 403 and an HTML page reading "You've been blocked by network security." So did the next three, with Reddit's recommended User-Agent format and with curl's default. Oddly, the 403 carried retry-after: 0.

Reddit's Data API wiki explains it: "Traffic not using OAuth or login credentials will be blocked, and the default rate limit will not apply."

Reddit Data API Wiki, Rate Limits section: monitor X-Ratelimit-Used, X-Ratelimit-Remaining and X-Ratelimit-Reset; the free limit is 100 queries per minute per OAuth client id, averaged over a 10-minute window; traffic not using OAuth or login credentials will be blocked, and the default rate limit will not apply
Reddit's Data API wiki on October 2, 2026: 100 queries a minute with OAuth, and a block without it.

With OAuth, the limit is 100 queries a minute per client ID, averaged over 10 minutes. Note that Reddit's X-Ratelimit-Reset counts seconds until the reset, while GitHub's is a timestamp. Same header name, different meaning.

Handle a 429 in code: Retry-After first, then backoff with jitter

Here's the order of checks:

  1. Retry-After present: wait that many seconds, or until that date.
  2. A rate-limit header says zero remaining: wait until its reset time. This catches GitHub's 403.
  3. Neither: wait a random time between zero and a cap that doubles with each try. The randomness is the jitter. It stops a hundred clients that failed together from all retrying together, as AWS's backoff and jitter write-up shows.
  4. Give up after a few tries and return the last response, so a stuck limit doesn't hang your job.
import random
import time
from email.utils import parsedate_to_datetime

import requests


def wait_seconds(response, attempt, base=1.0, cap=60.0):
    """How long to wait before the next try."""
    retry_after = response.headers.get("Retry-After")
    if retry_after:
        if retry_after.isdigit():
            return int(retry_after)
        # Retry-After can also be an HTTP date
        return max(0, parsedate_to_datetime(retry_after).timestamp() - time.time())
    reset = response.headers.get("X-RateLimit-Reset")
    if reset and response.headers.get("X-RateLimit-Remaining") == "0":
        return max(0, int(reset) - time.time())  # GitHub sends epoch seconds
    # No hint from the server: exponential backoff with full jitter
    return random.uniform(0, min(cap, base * 2 ** attempt))


def polite_get(url, max_tries=5, **kwargs):
    for attempt in range(max_tries):
        response = requests.get(url, **kwargs)
        rate_limited = response.status_code == 429 or (
            response.status_code == 403
            and response.headers.get("X-RateLimit-Remaining") == "0"
        )
        if not rate_limited or attempt == max_tries - 1:
            return response
        time.sleep(wait_seconds(response, attempt))

Both versions passed the same five cases against a local test server: Retry-After in seconds, Retry-After as a date, a GitHub-style 403, a 429 with no hints, and a 429 that never clears. The reset check assumes GitHub's timestamp. For Reddit's seconds-until-reset, add the value to the current time.

Backoff only helps you recover. To stop seeing 429s, send fewer requests: cache what you've already fetched, space calls out using the remaining-requests header, and use a key or token where the API offers one. GitHub's limit goes from 60 to 5,000 an hour with a token, and CoinGecko's free Demo key is 100 calls a minute.

The same Reddit reads with an API key

For Reddit, a token means registering an OAuth app under Reddit's terms. The other route is a hosted endpoint. I sent 100 reads to AnyAPI's reddit.subreddit_posts: 20 subreddits, from r/programming to r/sysadmin, each as hot, new, and top of the day, week, and year. They ran one after another, with no pause, from 22:17:15 to 22:20:53 UTC.

All 100 came back 200, with 2,244 posts between them, in a median of 2.2 seconds a call. The endpoint now costs $0.80 per 1,000 calls. Here's one call and its response, trimmed to one post:

curl -X POST https://api.getanyapi.com/v1/run/reddit.subreddit_posts \
  -H "Authorization: Bearer $ANYAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subreddit": "programming", "sort": "hot", "limit": 25}'
{
  "output": {
    "found": true,
    "data": {
      "posts": [
        {
          "id": "1wv4hph",
          "subreddit": "programming",
          "title": "New Python releases are out, 3.10.x reaches EOL, (and 3.15.0 is scheduled for today)!",
          "score": 90,
          "numComments": 14,
          "upvoteRatio": 0.9166666666666666,
          "permalink": "/r/programming/comments/1wv4hph/new_python_releases_are_out_310x_reaches_eol_and/",
          "createdUtc": 1790873133
        }
      ],
      "nextCursor": "cur_nSkYM69VIvI1p2exrns-UQ"
    }
  },
  "costUsd": 0.00038,
  "items": 25
}

Pass nextCursor back as cursor for the next page. On October 2, the 100 calls cost $0.038 in total, $0.00038 each.

How this compares to what is already published

  • Firecrawl's glossary entry explains rate-limit algorithms, the Retry-After and X-RateLimit headers, throttling, proxies, and doubling backoff, and how a 429 differs from a 403.
  • ZenRows' guide shows an example 429 with RateLimit-* headers and works through fixes for scrapers, ending with its own scraping API.
  • Scrapfly's answer is a short definition with two fixes, rate limiting and rotating proxies.
  • MDN's 429 page is the reference definition, with an example response.

All four describe a typical 429. None of them shows what named free APIs actually sent back, and that's where they differ from this test: the one real 429 here came from CoinGecko, while GitHub and Reddit said no with a 403. A handler that waits on 429 alone would have treated GitHub's limit as a permanent error.

How I measured it

  1. One connection, one request a second. All free tests ran on October 2, 2026, from one residential IP, with a User-Agent naming the study and a contact address.
  2. Stop at the first refusal. CoinGecko and GitHub got requests until the first non-200 response, which was saved with all its headers. Reddit refused the first request, and three more tried other User-Agents.
  3. Check the reset. One request after CoinGecko's Retry-After ran out, and one after GitHub's reset time.
  4. Read each service's docs for its stated limit, on the same day.
  5. 100 paid reads. 20 subreddits times five listings through reddit.subreddit_posts, in sequence, each logged with status, time, and charge.

The free tests cost nothing. The Reddit reads ran through AnyAPI's Reddit endpoints and cost $0.038.

The limits of this data

  • One IP on one day. Limits that are counted per IP depend on what else shares it, and CoinGecko doesn't publish its keyless number, so you may get more or fewer than 5.
  • GitHub's headers showed two separate counters during the run, each with its own reset time. The refused request came when one of them reached 60, which matches the documented limit, but more requests went through in total before the refusal.
  • Reddit was tested only without OAuth, so its 100-a-minute limit wasn't measured.
  • The 100 AnyAPI calls ran one at a time. They show that sequential reads went through, not how many parallel requests a key can make.

GitHub's 60-an-hour number is solid because the headers and docs agree. The CoinGecko figure is a single observation.

What to do with it

  1. Treat 429, and 403 with zero remaining, as "wait". Read the body of any other 403 before you retry it on a timer.
  2. Honour Retry-After in both forms, then fall back to jittered backoff with a retry cap.
  3. Read each API's reset header from its own docs, because GitHub and Reddit use the same name for different things.
  4. Get a key or token where the API offers one: GitHub goes from 60 to 5,000 requests an hour.
  5. If an API blocks scripts outright, as Reddit's public JSON did, use its OAuth route or a hosted endpoint.

Frequently asked questions

What does 429 Too Many Requests mean?
The server got more requests from you than it allows in a stretch of time, so it refused this one. It's temporary. The response may carry a Retry-After header that says how many seconds to wait, or the date and time to try again.
How long does a 429 error last?
As long as the server's window. On October 2, 2026, CoinGecko's keyless API asked for 60 seconds after its 429, and GitHub's unauthenticated API refused for 58 minutes, until one hour after the first request it counted. Read Retry-After or the reset header rather than guessing.
How do I fix 429 Too Many Requests on a website?
Stop refreshing and wait a few minutes, because every retry can count against the same limit. If it keeps happening, turn off your VPN or switch networks, since many limits are counted per IP address and a shared address carries other people's requests too. Signing in can help where the site gives accounts their own limit.
Is a 429 the same as being banned?
No. A 429 says wait and try again. A block often comes back as a 403 instead, like the 'You've been blocked by network security' page Reddit returned to our script on the first request. Reddit's docs say traffic without OAuth 'will be blocked'.
Should I retry a 429 immediately?
No. Wait for the Retry-After value when there is one. Without it, wait an exponentially growing, randomized time and give up after a few tries. CoinGecko's docs say every request counts toward its per-minute limit, errors included, so instant retries only use up more of it.

For more on Reddit's official route, see Is the Reddit API free?. To give an AI assistant Reddit access, see the Reddit MCP server guide.

Subreddit listings as JSON, $0.0008 a call, with no Reddit app to register. New accounts get free credit, no card required.

Try the Reddit Subreddit Posts API

Use data responsibly and follow AnyAPI's Acceptable Use Policy.