Errors

Understand API error responses and how to recover from common scraping failures.

ScrapeRouter uses conventional HTTP response codes for API-level failures such as validation, authentication, credits, concurrency, and platform timeouts. A completed scrape attempt returns HTTP 200; target-level failures are represented inside the JSON body via status_code and errors.

HTTP status codes

Status Description
200 ScrapeRouter completed the scrape attempt. Inspect JSON status_code and errors for the target result.
400 Bad request - invalid parameters or malformed JSON
401 Unauthorized - missing or invalid API key
402 Payment required - insufficient credits
429 Too many requests - concurrency or rate limit exceeded
500 Internal server error
504 ScrapeRouter processing timed out before a result could be returned

Scrape result failures

A response like HTTP 200 with JSON status_code: 504 means the ScrapeRouter API completed successfully, but the selected scraper or target request timed out. Client code should treat errors as failure context and should not rely on HTTP status alone.

Error response format

Error responses include an errors array with one or more normalized error objects:

{
  "errors": [
    {
      "code": "authentication_required",
      "message": "Authentication credentials were not provided",
      "field": null,
      "details": null
    }
  ]
}

Payment errors (402) use the same normalized envelope:

{
  "errors": [
    {
      "code": "insufficient_credits",
      "message": "Insufficient credits",
      "field": null,
      "details": null
    }
  ]
}

Validation errors may return multiple field-specific entries in errors:

{
  "errors": [
    {
      "code": "invalid_field",
      "message": "Input should be a valid URL, relative URL without a base",
      "field": "url",
      "details": null
    },
    {
      "code": "invalid_field",
      "message": "Scraper 'invalid' not found",
      "field": "scraper",
      "details": null
    }
  ]
}

Handling errors

import requests

response = requests.post(
    "https://www.scraperouter.com/api/v1/scrape/",
    headers={"Authorization": "Api-Key {your_api_key}"},
    json={"url": "https://example.com", "scraper": "auto"},
)
data = response.json()

if response.status_code == 429:
    print("Rate limited, retrying...")
elif not response.ok:
    print(f"API error {response.status_code}: {data}")
elif data.get("errors") or not (200 <= (data.get("status_code") or 0) < 400):
    print(f"Scrape failed: {data.get('status_code')} {data.get('errors')}")
else:
    print(data["content"])
const response = await fetch("https://www.scraperouter.com/api/v1/scrape/", {
  method: "POST",
  headers: {
    "Authorization": "Api-Key {your_api_key}",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ url: "https://example.com", scraper: "auto" }),
});
const data = await response.json();

if (response.status === 429) {
  console.log("Rate limited, retrying...");
} else if (!response.ok) {
  console.error(`API error ${response.status}:`, data);
} else if (data.errors?.length || data.status_code < 200 || data.status_code >= 400) {
  console.error("Scrape failed:", data.status_code, data.errors);
} else {
  console.log(data.content);
}