# ZenRows' Python client against SpecStream

Date: 2026-11-10. Client: zenrows 1.13.0.

## The one line a user changes

Before:

```
client = ZenRowsClient("...")
```

After:

```
client = ZenRowsClient(KEY, base_url="https://api.specstream.ai/zenrows/v1/")
```

One call is one Extract API page read at $0.0008; a failed page is not charged.
ZENROWS_SCRAPER_BASE_URL set to the same address works the same way.

## Request parameters

Honoured means the check in the Measured column passed on the reply. Accepted, not applied means status 200 and the reply has the form of the same call without the parameter. Refused means the vendor's error body and status.

Counts: 7 honoured, 23 accepted, not applied, 4 refused.

| Parameter | Sent | Verdict | Measured |
|---|---|---|---|
| `url` | `https://en.wikipedia.org/wiki/Web_scraping` | honoured | status 200; the body is the page's HTML |
| `apikey` | the key in the query, as the client sends it | honoured | status 200; answered with the page |
| `response_type` | `markdown` | honoured | status 200; the body is markdown, not HTML |
| `response_type` | `plaintext` | honoured | status 200; the body is plain text |
| `json_response` | `true` | honoured | status 200; a JSON object whose html is the page |
| `outputs` | `links,emails` | honoured | status 200; 335 links, emails [] |
| `outputs` | `headings,images` | accepted, not applied | status 200; keys []: the read fills neither |
| `url (a page the site does not have)` | a 404 page | honoured | status 404; ZenRows' 404 RESP002 |
| `url (a host that does not resolve)` | an unknown host | refused | status 422; ZenRows' 422 RESP001 |
| `mode` | `auto` with js_render | refused | status 400; ZenRows refuses the pair (REQS004) |
| `mode` | `auto` | accepted, not applied | status 200; the reply is the baseline's page |
| `js_render` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `js_instructions` | `[{"wait": 500}]` | accepted, not applied | status 200; the reply is the baseline's page |
| `premium_proxy` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `proxy_country` | `de` | accepted, not applied | status 200; the reply is the baseline's page |
| `session_id` | `123` | accepted, not applied | status 200; the reply is the baseline's page |
| `original_status` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `allowed_status_codes` | `404` | accepted, not applied | status 200; the reply is the baseline's page |
| `wait_for` | `#content` | accepted, not applied | status 200; the reply is the baseline's page |
| `wait` | `1000` | accepted, not applied | status 200; the reply is the baseline's page |
| `block_resources` | `image,media` | accepted, not applied | status 200; the reply is the baseline's page |
| `custom_headers` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `css_extractor` | `{"title": "h1"}` | accepted, not applied | status 200; the reply is the baseline's page |
| `autoparse` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `extract` | `auto` | accepted, not applied | status 200; the reply is the baseline's page |
| `extract_fields` | `title` | accepted, not applied | status 200; the reply is the baseline's page |
| `response_type` | `pdf` | accepted, not applied | status 200; the reply is the baseline's page |
| `screenshot` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `screenshot_fullpage` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `screenshot_selector` | `#content` | accepted, not applied | status 200; the reply is the baseline's page |
| `screenshot_format` | `jpeg` | accepted, not applied | status 200; the reply is the baseline's page |
| `screenshot_quality` | `50` | accepted, not applied | status 200; the reply is the baseline's page |
| `apikey (wrong key)` | a key that is not one | refused | status 401; ZenRows' 401 AUTH002 |
| `url (missing)` | no url | refused | status 400; ZenRows' 400 REQS004 |

## Response fields

Present means the field holds a value in the replies to the calls above. Empty means it is there with no value. Absent means it is not in the reply.

Counts: 9 present, 1 empty, 8 absent.

| Field | State | Measured |
|---|---|---|
| `body` | present | every 200 reply |
| `X-Request-Id header` | absent | every 200 reply |
| `X-Request-Cost header` | absent | every 200 reply |
| `Zr-Final-Url header` | absent | every 200 reply |
| `Concurrency-Limit header` | absent | every 200 reply |
| `Concurrency-Remaining header` | absent | every 200 reply |
| `html (json_response)` | present | the json_response reply |
| `xhr (json_response)` | absent | the json_response reply |
| `links (outputs)` | present | the outputs reply |
| `emails (outputs)` | empty | the outputs reply |
| `headings (outputs)` | absent | the outputs reply |
| `images (outputs)` | absent | the outputs reply |
| `error code` | present | every refused call |
| `error status` | present | every refused call |
| `error title` | present | every refused call |
| `error detail` | present | every refused call |
| `error type` | present | every refused call |
| `error instance` | present | every refused call |
