What causes a 429 error
- Too many requests in a short time from one IP address, account, API key or session. Each service decides what it counts and how long the window is; RFC 6585 leaves that to the server.
- Too many requests at once. High concurrency can trip a limit even when the total per minute looks reasonable.
- Retries that pile up. Retrying failures straight away, often from several workers at once, multiplies the load at the worst moment.
- Shared limits. On a shared IP address or a shared API key, other traffic counts toward the same limit.
- Expensive endpoints. Search, sign-in and export endpoints often have much lower limits than ordinary pages.
How to read Retry-After
Retry-After holds either a number of seconds (Retry-After: 120) or an HTTP date (Retry-After: Wed, 21 Oct 2026 07:28:00 GMT), as defined in RFC 9110, section 10.2.3. Handle both. If it's missing, back off on your own: wait a second or two, double the wait after each 429, and add a little random jitter so many workers don't retry at the same moment.
Some APIs also send headers such as RateLimit-Remaining or X-RateLimit-Remaining that show how much of the limit is left. They differ from API to API, so check that API's docs.
Did the proxy or the site send the 429?
For an https:// URL your client first asks the proxy to open a tunnel with a CONNECT request. A status sent in reply to CONNECT, before the tunnel opens, comes from the proxy, and nothing reached the site; Python requests raises a ProxyError for it instead of returning a response. Once the tunnel is open, the proxy only relays encrypted bytes, so a status that comes back as a normal response came from the site's side: its server, load balancer or CDN.
So a 429 that comes back as a normal response on an https:// URL is the site's rate limit (or its CDN's).
On BuyProxy, the API's own limit is 60 requests a minute per API key, and it applies only to management calls such as generating lines and checking balances. Traffic through your proxy lines doesn't count toward it. A 429 from www.buyproxy.org/v1 carries Retry-After: the seconds left in the key's current window. See API rate limits.
How to fix a 429 error
- Stop and wait. Honour
Retry-Afterwhen it is there. On some services, requests sent during the wait extend the limit. - Back off exponentially with jitter when there is no
Retry-After: 1, 2, 4, 8 seconds and so on, each with a random fraction added, up to a cap. - Lower concurrency per site. Cap the number of requests in flight to one host, and spread a job over a longer time.
- Cache and deduplicate. Don't fetch the same page twice in one run, and use conditional requests (
If-None-Match,If-Modified-Since) where the site supports them. - Use the official API if there is one. It usually has published limits and is meant for automated access.
- Read
robots.txtand the terms. Some sites state the crawl rate they accept, in their terms or with aCrawl-delayline inrobots.txt.
Retry with backoff that honours Retry-After
# --retry repeats on timeouts and on 408, 429, 500, 502, 503 and 504 responses.
# curl 7.66.0 and later wait for Retry-After when the server sends one;
# otherwise the wait starts at 1 second and doubles after each try.
curl --retry 5 --retry-max-time 300 -x "http://USERNAME:PASSWORD@HOST:PORT" https://example.com/import random
import time
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime
import requests
RETRY_STATUSES = {429, 502, 503, 504}
def retry_after_seconds(value):
"""Seconds to wait from a Retry-After header: a number of seconds or an HTTP date."""
if not value:
return None
value = value.strip()
if value.isdigit():
return int(value)
try:
when = parsedate_to_datetime(value)
return max(0.0, (when - datetime.now(timezone.utc)).total_seconds())
except (TypeError, ValueError):
return None
def get_with_backoff(url, proxies=None, attempts=5, max_wait=120):
response = None
for attempt in range(attempts):
response = requests.get(url, proxies=proxies, timeout=30)
if response.status_code not in RETRY_STATUSES or attempt == attempts - 1:
break
wait = retry_after_seconds(response.headers.get("Retry-After"))
if wait is None:
wait = min(60, 2 ** attempt) + random.uniform(0, 1) # exponential backoff with jitter
if wait > max_wait:
break # a longer pause than this job allows: stop and come back later
time.sleep(wait)
return response
proxy = "http://USERNAME:PASSWORD@HOST:PORT"
r = get_with_backoff("https://example.com/", proxies={"http": proxy, "https": proxy})
print(r.status_code)The function retries only 429, 502, 503 and 504, and raises anything else to you. A requests.exceptions.ProxyError (a refused CONNECT, or a proxy that can't be reached) is raised too, not retried: if it says 407, retrying the same credentials can't succeed.
429 errors when you use proxies
A rate limit is a site telling you how much traffic it will accept. Spreading the same volume across many IP addresses to stay under a per-IP limit goes against that, and BuyProxy's acceptable use policy asks you to respect rate limits. Many sites also count by account, session or API key, not only by IP. The fix is the one above: send fewer requests, more slowly.
Rotating and sticky sessions still matter. With a rotating line, each request can leave from a different IP, which suits independent page fetches at a polite rate. With a sticky session, your requests share one IP, so the site sees one visitor and its per-IP limit covers all of them: pace the session to match. On Core Residential, sticky is on or off and usually keeps the same IP for around 10 minutes; on Premium Residential you set the length, from 3 minutes to 24 hours. See session types.
Keep the retry logic in your client, with a cap, not in a loop that keeps sending. Retries count toward the limit too.
429 Too Many Requests: frequently asked questions
What does error 429 mean?
Too Many Requests: you sent more requests than the server allows in a period of time. Wait, then send requests more slowly.
How long should I wait after a 429?
As long as the Retry-After header says, if the response has one; it is either a number of seconds or a date. Without it, start with a second or two and double the wait after each 429, up to a cap.
Is a 429 a ban?
No. It is a temporary limit. Ignoring it again and again can lead a site to block you for longer, so slow down rather than retrying straight away.
Does a 429 come from my proxy?
Rarely. A 429 inside an HTTPS tunnel comes from the site or its CDN. The BuyProxy API has its own limit of 60 requests a minute per key, but it applies only to API calls, not to traffic through your proxy lines.
Should I rotate IPs to stop getting 429 errors?
No. A 429 is the site's limit on how much traffic it accepts. Lower your request rate and concurrency, honour Retry-After, and use the site's API where there is one.