Basic usage
Retries are off by default (retries=0). Pass a retries count to the client constructor to turn them on:
retries=2, a failed request is attempted up to 2 additional times (3 attempts total) before the SDK returns the last response it received.
When to enable retries
Enableretries (2–3 is a reasonable starting point) whenever you’re running requests at scale or in production. Anywhere a transient 429 or 5xx shouldn’t fail your whole job. Leave retries=0 (the default) for quick one-off scripts or debugging, where you’d rather see the raw failure immediately than wait through automatic retry attempts.
Which failures get retried
The SDK retries requests that come back with one of these status codes:| Status code | Meaning |
|---|---|
422 | Unprocessable Entity |
429 | Too Many Requests |
500 | Internal Server Error |
502 | Bad Gateway |
503 | Service Unavailable |
504 | Gateway Timeout |
Handling failures
The SDK treats HTTP error status codes and network-level problems differently. Pick the tab that matches what you’re dealing with:- HTTP error status
- Network-level exceptions
Even after all retry attempts are exhausted, the SDK returns the final If you’d rather fail loudly, call
requests.Response object. It does not raise an exception for a non-2xx status. Always check the response before trusting its content:response.raise_for_status(), which raises requests.exceptions.HTTPError for 4xx/5xx responses:Troubleshooting
- Response still fails after retries are exhausted: Check
response.status_codeand look it up in API Error Codes. Some failures (like an invalidapikey) won’t be fixed by retrying and need a code change instead. - Retries seem to take a long time: That’s the exponential backoff by design. Lower
retriesif latency matters more than success rate for your use case. - Getting exceptions instead of error responses: That only happens for network-level failures (timeouts, DNS errors), not HTTP error status codes. Wrap the call in
try/except requests.exceptions.RequestExceptionas shown above. - 429 errors even with retries enabled: You’re likely exceeding your plan’s concurrency limit, not hitting a one-off rate limit. See Async Requests and Concurrency.
Pricing
Retried attempts that fail are not billed. Only the final successful response counts. This makesretries effectively free insurance against transient failures:
| Configuration | Cost multiplier vs. basic |
|---|---|
| Basic request | 1x |
js_render=True | 5x |
premium_proxy=True | 10x |
js_render=True + premium_proxy=True | 25x |
404 and 410 responses count as successful and are billed, since the request itself completed correctly.FAQ
What's the default number of retries?
What's the default number of retries?
The default number of retries is 0. Retries are disabled unless you explicitly pass
retries=N to the constructor.Am I charged for retried requests that eventually fail?
Am I charged for retried requests that eventually fail?
No. Only successful requests consume your ZenRows balance.
Does the SDK retry on connection timeouts automatically?
Does the SDK retry on connection timeouts automatically?
Connection-level failures raise a
requests exception rather than returning a response, so they’re not covered by the retries status-code list. Handle them with your own try/except, as shown above.Look up a specific error code
For a full breakdown of ZenRows error codes (likeAUTH002 or RESP001) and how to resolve each one, see the API Error Codes reference.