Skip to main content
Every method on ZenRowsClient (get, post, put, and their _async counterparts) returns a standard requests.Response object. The SDK doesn’t wrap or transform it, so everything you already know about requests applies directly.

Commonly used attributes

AttributeReturnsUse it when
response.textResponse body as a stringReading HTML or plain text
response.contentResponse body as raw bytesHandling binary data (PDFs, screenshots, images)
response.json()Parsed JSONThe body is JSON (e.g. json_response=true)
response.status_codeHTTP status code, e.g. 200Checking exactly what happened
response.okTrue if status_code is under 400Quick success check
response.headersDict-like object of response headersReading ZenRows monitoring headers
response.request.urlThe final URL that was requestedDebugging what was actually sent
response = client.get(url)
html = response.text

Reading ZenRows-specific headers

ZenRows adds monitoring headers to every response, useful for debugging and tracking usage:
response = client.get(url)

print(response.headers.get("X-Request-Id"))          # unique ID for this request
print(response.headers.get("X-Request-Cost"))        # dollar cost of this request (e.g., 0.001)
print(response.headers.get("X-Request-Credits"))     # number of credits consumed by this request
print(response.headers.get("Concurrency-Remaining"))  # concurrency slots left on your plan
print(response.headers.get("Zr-Final-Url"))           # final URL after redirects
If you ever contact ZenRows support about a failed request, include the X-Request-Id header value. It lets the team trace the exact request in the logs.
Headers coming from the target website itself are prefixed with Zr- to distinguish them from ZenRows’ own headers. See the full list in the Universal Scraper API setup guide.

Checking success before using the body

Because the SDK returns the response as-is rather than raising on error status codes, always confirm the request succeeded first:
response = client.get(url)

if response.ok:
    data = response.text
else:
    print(f"Request failed: {response.status_code}")

Error Handling and Retries

More on this pattern, plus how to configure automatic retries.

Troubleshooting

  • response.json() raises JSONDecodeError: The body isn’t JSON. Confirm you requested json_response=true or that the target actually returns JSON before calling .json().
  • Saved file (PDF, screenshot, image) is corrupted: You wrote response.text instead of response.content, or opened the file in text mode ("w") instead of binary ("wb").
  • response.headers.get("X-Request-Id") returns None: The header name is case-insensitive in requests, so this shouldn’t normally happen; confirm the request actually reached ZenRows (check response.status_code first) rather than failing at the network layer.
  • response.request.url doesn’t match the URL you passed: This is expected. It’s the full URL sent to ZenRows’ API (including your apikey and params as query parameters), not the target URL by itself.

Pricing

The response itself doesn’t add cost. ZenRows adds two headers to help you track usage:
  • X-Request-Cost: the dollar cost of the request (e.g., 0.001)
  • X-Request-Credits: the number of credits consumed by the request
Both values are based on the params used:
ConfigurationCost multiplier vs. basic
Basic request1x
js_render=True5x
premium_proxy=True10x
js_render=True + premium_proxy=True25x
See ZenRows Pricing.

FAQ (Frequently Asked Questions)

No. It’s the standard requests.Response object from Python’s requests library. Any requests documentation or Stack Overflow answer about it applies here too.
Call response.json() if the body is JSON. For example, when using json_response=true or autoparse=true on structured data.
Check the response headers: X-Request-Cost gives you the dollar cost (e.g., 0.001), and X-Request-Credits gives you the number of credits consumed.