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
| Attribute | Returns | Use it when |
|---|---|---|
response.text | Response body as a string | Reading HTML or plain text |
response.content | Response body as raw bytes | Handling binary data (PDFs, screenshots, images) |
response.json() | Parsed JSON | The body is JSON (e.g. json_response=true) |
response.status_code | HTTP status code, e.g. 200 | Checking exactly what happened |
response.ok | True if status_code is under 400 | Quick success check |
response.headers | Dict-like object of response headers | Reading ZenRows monitoring headers |
response.request.url | The final URL that was requested | Debugging what was actually sent |
- Text / HTML
- Binary (PDF, screenshot)
- JSON
Reading ZenRows-specific headers
ZenRows adds monitoring headers to every response, useful for debugging and tracking usage: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:Error Handling and Retries
More on this pattern, plus how to configure automatic retries.
Troubleshooting
response.json()raisesJSONDecodeError: The body isn’t JSON. Confirm you requestedjson_response=trueor that the target actually returns JSON before calling.json().- Saved file (PDF, screenshot, image) is corrupted: You wrote
response.textinstead ofresponse.content, or opened the file in text mode ("w") instead of binary ("wb"). response.headers.get("X-Request-Id")returnsNone: The header name is case-insensitive inrequests, so this shouldn’t normally happen; confirm the request actually reached ZenRows (checkresponse.status_codefirst) rather than failing at the network layer.response.request.urldoesn’t match the URL you passed: This is expected. It’s the full URL sent to ZenRows’ API (including yourapikeyandparamsas 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
params used:
| Configuration | Cost multiplier vs. basic |
|---|---|
| Basic request | 1x |
js_render=True | 5x |
premium_proxy=True | 10x |
js_render=True + premium_proxy=True | 25x |
FAQ (Frequently Asked Questions)
Is the response object specific to ZenRows?
Is the response object specific to ZenRows?
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.How do I get the response as a Python dict?
How do I get the response as a Python dict?
Call
response.json() if the body is JSON. For example, when using json_response=true or autoparse=true on structured data.Where do I find how much a request cost?
Where do I find how much a request cost?
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.