# ScrapingBee's Python client against SpecStream

Date: 2026-11-10. Client: scrapingbee 2.2.0.

## The one line a user changes

Before:

```
client = ScrapingBeeClient(api_key="...")
```

After:

```
client = ScrapingBeeClient(api_key=KEY)
client.HTML_API_URL = "https://api.specstream.ai/scrapingbee/api/v1/"
```

One call is one Extract API page read at $0.0008; a page with HTML and no main text is answered and not charged, and a failed page is not charged.
A request with no credits left answers 401, as ScrapingBee does.

## 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: 9 honoured, 30 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 |
| `Authorization: Bearer header` | the client's own header | honoured | status 200; answered with the page |
| `api_key` | the key in the query, no header | honoured | status 200; answered with the page |
| `return_page_markdown` | `true` | honoured | status 200; the body is markdown, not HTML |
| `return_page_text` | `true` | honoured | status 200; the body is plain text |
| `json_response` | `true` | honoured | status 200; a JSON object with body and initial-status-code |
| `add_html` | `true` with json_response and return_page_markdown | honoured | status 200; html holds the page, body its markdown |
| `url (a page the site does not have)` | a 404 page | honoured | status 404; the site's 404 passes through |
| `transparent_status_code` | `true` on a 404 page | honoured | status 404; the site's status |
| `url (a host that does not resolve)` | an unknown host | refused | status 500; ScrapingBee's 500 for a page it could not get |
| `mode` | `auto` with render_js | refused | status 400; ScrapingBee refuses the pair |
| `render_js` | `false` | 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 |
| `stealth_proxy` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `country_code` | `de` | 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 |
| `wait_for` | `#content` | accepted, not applied | status 200; the reply is the baseline's page |
| `wait_browser` | `load` | accepted, not applied | status 200; the reply is the baseline's page |
| `block_ads` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `block_resources` | `false` | accepted, not applied | status 200; the reply is the baseline's page |
| `window_width` | `1280` | accepted, not applied | status 200; the reply is the baseline's page |
| `window_height` | `800` | accepted, not applied | status 200; the reply is the baseline's page |
| `device` | `mobile` | accepted, not applied | status 200; the reply is the baseline's page |
| `timeout` | `60000` | 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 |
| `return_page_source` | `true` | 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_full_page` | `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 |
| `extract_rules` | `{"title": "h1"}` | accepted, not applied | status 200; the reply is the baseline's page |
| `ai_query` | `who wrote it` | accepted, not applied | status 200; the reply is the baseline's page |
| `ai_selector` | `#content` | accepted, not applied | status 200; the reply is the baseline's page |
| `ai_extract_rules` | `{"summary": "a one line summary"}` | accepted, not applied | status 200; the reply is the baseline's page |
| `js_scenario` | `{"instructions": [{"wait": 500}]}` | accepted, not applied | status 200; the reply is the baseline's page |
| `cookies` | `{"a": "1"}` | accepted, not applied | status 200; the reply is the baseline's page |
| `own_proxy` | `http://user:pass@proxy.example:8080` | accepted, not applied | status 200; the reply is the baseline's page |
| `tag` | `proof` | accepted, not applied | status 200; the reply is the baseline's page |
| `scraping_config` | `saved` | accepted, not applied | status 200; the reply is the baseline's page |
| `max_cost` | `5` | accepted, not applied | status 200; the reply is the baseline's page |
| `mode` | `auto` | accepted, not applied | status 200; the reply is the baseline's page |
| `forward_headers_pure` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `api key (wrong key)` | a key that is not one | refused | status 401; ScrapingBee's 401 |
| `url (missing)` | no url | refused | status 400; ScrapingBee's 400 |

## 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: 7 present, 0 empty, 13 absent.

| Field | State | Measured |
|---|---|---|
| `body (default reply)` | present | every 200 reply that is not JSON |
| `content-type header` | present | every 200 reply that is not JSON |
| `Spb-cost header` | absent | every 200 reply that is not JSON |
| `Spb-initial-status-code header` | absent | every 200 reply that is not JSON |
| `Spb-resolved-url header` | absent | every 200 reply that is not JSON |
| `Spb-request-id header` | absent | every 200 reply that is not JSON |
| `body` | present | json_response replies |
| `initial-status-code` | present | json_response replies |
| `resolved-url` | present | json_response replies |
| `type` | present | json_response replies |
| `html` | present | json_response replies |
| `headers` | absent | json_response replies |
| `cost` | absent | json_response replies |
| `cookies` | absent | json_response replies |
| `xhr` | absent | json_response replies |
| `screenshot` | absent | json_response replies |
| `metadata` | absent | json_response replies |
| `iframes` | absent | json_response replies |
| `evaluate_results` | absent | json_response replies |
| `js_scenario_report` | absent | json_response replies |
