Scraping API error codes explained: what each one means, whether to retry, and what it costs
Every error is a status plus a short code and a sentence. The full list: the cause of each one, whether a retry helps, and which ones refund the credit.
In short
- Errors are JSON: { error: { code, message } }. The code is stable and meant for your if-statements; the message is for humans.
- 4xx codes are about your request or your account and never fix themselves with a retry. 5xx codes are about the target site or the service and often do.
- Failures caused on this side refund the credit: RENDER_UNAVAILABLE, INTERNAL_ERROR, SITE_BLOCKED and SITE_PARSE_FAILED. A dead or slow target site (FETCH_FAILED, TIMEOUT) is charged, because the fetch was made.
An error you can branch on is worth more than one you can read. Every failure from this API therefore carries a short, stable code next to a plain sentence, and the HTTP status tells you which side the problem is on.
{ "error": { "code": "QUOTA_EXCEEDED", "message": "Daily credit limit reached. Resets at 2026-09-23T00:00:00Z." } }
The full list
| Status | Code | Cause | Retry? | Credit |
|---|---|---|---|---|
| 400 | BAD_REQUEST | a parameter is missing, malformed or out of range; the message names it | no, fix the request | not charged |
| 400 | URL_BLOCKED | the URL targets a private or reserved network, localhost, or a non-http scheme | no | not charged |
| 401 | UNAUTHORIZED | no API key, or a key that does not exist | no, check the key | not charged |
| 403 | FORBIDDEN | the key was revoked, or the account is not allowed to do this | no | not charged |
| 404 | NOT_FOUND | unknown site or action on a structured endpoint, or a site said the item does not exist | no | charged on site endpoints |
| 429 | RATE_LIMITED | more than 60 requests in a minute on one key | yes, after a few seconds | not charged |
| 429 | QUOTA_EXCEEDED | the account’s daily credits are used up | after the reset time in the message | not charged |
| 502 | FETCH_FAILED | the target could not be reached: DNS, connection refused, TLS, too many redirects | yes, later | charged |
| 502 | SITE_PARSE_FAILED | the page arrived but the parser could not read it; usually a layout change | yes, and tell the board | refunded |
| 503 | SITE_BLOCKED | the target served a CAPTCHA or a bot wall instead of the page | yes, after a minute or more | refunded |
| 503 | RENDER_UNAVAILABLE | render=true was asked for while the browser pool is down | yes, or drop render | refunded |
| 504 | TIMEOUT | the target did not answer within timeout (default 15 s, max 30 s) | yes, perhaps with a longer timeout | charged |
| 500 | INTERNAL_ERROR | a bug on this side | yes; it is logged and looked at | refunded |
The rule behind the credit column
You pay for a fetch that was made on your behalf. If the target site is down or slow, the fetch was made and the credit stands, exactly as it would if you had made the request yourself. If the failure is caused here, because the parser is out of date, the browser pool is unavailable, or a cloud address was blocked by the site, the credit is returned; that was not something you could have avoided.
Successful responses that carry a target status of 404 or 500 are not errors. /v1/scrape returns 200 with the target’s statusCode in the body, because fetching a page that says “not found” is a successful fetch.
A retry policy that works
RATE_LIMITED → wait 2–5 s, retry
SITE_BLOCKED → wait 60 s+, retry once; or accept a stored copy (max_age)
FETCH_FAILED → retry once after 10 s; then give up, the site is down
TIMEOUT → retry once with a larger timeout (up to 30000)
SITE_PARSE_FAILED → do not loop; post the URL on the board
4xx (others) → fix the request or the key; retrying repeats the error
Log the code, not the message; messages may be reworded, codes will not.
Where errors show up in the dashboard
Every request, successful or not, is a row in the dashboard’s log with its code, status, host and timing, kept for 30 days. If you see a run of SITE_PARSE_FAILED on one site, that is the moment to say so on the board; parsers are fixed once, for everyone. The error reference is the short version of this page.
Questions people ask
- What is the difference between RATE_LIMITED and QUOTA_EXCEEDED?
- RATE_LIMITED is per minute and per key (60 requests); wait a few seconds. QUOTA_EXCEEDED is the daily credit cap for the whole account; it resets at 00:00 UTC and the message says when.
- Should I retry SITE_BLOCKED?
- Later, yes, with a pause of at least a minute; the site is refusing cloud traffic and hammering it makes that worse. For site endpoints, consider accepting a stored copy with a larger max_age instead.
- What does URL_BLOCKED mean?
- The URL points at something the API will not fetch: private networks, localhost, link-local addresses, non-http schemes. It is a safety rule, not a temporary state.
- Is a 4xx from the target site an error?
- No. If the target answers 404 or 403, /v1/scrape returns 200 with statusCode: 404 in the body, because the fetch itself succeeded. Errors are about the API's own work.