# Scrape.do's documented calls against SpecStream

Date: 2026-11-10. Client: requests (Scrape.do's documented HTTP calls; it publishes no client library that takes another address) 2.34.2.

## The one line a user changes

Before:

```
https://api.scrape.do/?token=TOKEN&url=URL
```

After:

```
https://api.specstream.ai/scrapedo?token=KEY&url=URL
```

One call is one Extract API page read at $0.0008; a failed page is not charged.
A request with no credits left answers 401, as Scrape.do 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: 7 honoured, 28 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 |
| `token` | the key in the query | honoured | status 200; answered with the page |
| `output` | `markdown` | honoured | status 200; the body is markdown |
| `output` | `raw` | honoured | status 200; the body is the page's HTML |
| `returnJSON` | `true` with render | honoured | status 200; a JSON object whose content is the page |
| `returnJSON` | `true` without render | refused | status 400; Scrape.do needs render=true with it |
| `url (a page the site does not have)` | a 404 page | honoured | status 404; Scrape.do's 404 for a target not found |
| `transparentResponse` | `true` on a 404 page | honoured | status 404; the target's status |
| `url (a host that does not resolve)` | an unknown host | refused | status 502; Scrape.do's 502, not charged |
| `super` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `geoCode` | `de` | accepted, not applied | status 200; the reply is the baseline's page |
| `regionalGeoCode` | `europe` | accepted, not applied | status 200; the reply is the baseline's page |
| `sessionId` | `123` | accepted, not applied | status 200; the reply is the baseline's page |
| `customHeaders` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `extraHeaders` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `forwardHeaders` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `setCookies` | `a=1` | accepted, not applied | status 200; the reply is the baseline's page |
| `disableRedirection` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `timeout` | `30000` | accepted, not applied | status 200; the reply is the baseline's page |
| `retryTimeout` | `10000` | accepted, not applied | status 200; the reply is the baseline's page |
| `disableRetry` | `true` | 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 |
| `render` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `waitUntil` | `load` | accepted, not applied | status 200; the reply is the baseline's page |
| `customWait` | `500` | accepted, not applied | status 200; the reply is the baseline's page |
| `waitSelector` | `#content` | accepted, not applied | status 200; the reply is the baseline's page |
| `width` | `1280` | accepted, not applied | status 200; the reply is the baseline's page |
| `height` | `800` | accepted, not applied | status 200; the reply is the baseline's page |
| `blockResources` | `false` | 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 |
| `fullScreenShot` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `particularScreenShot` | `#content` | accepted, not applied | status 200; the reply is the baseline's page |
| `playWithBrowser` | `[{"Action":"Wait","Timeout":500}]` | accepted, not applied | status 200; the reply is the baseline's page |
| `pureCookies` | `true` | accepted, not applied | status 200; the reply is the baseline's page |
| `callback` | `https://hooks.example/scrapedo` | accepted, not applied | status 200; the reply is the baseline's page |
| `showFrames` | `true` with render and returnJSON | accepted, not applied | status 200; frames in the reply |
| `showWebsocketRequests` | `true` with render and returnJSON | accepted, not applied | status 200; websocket logs in the reply |
| `token (wrong key)` | a key that is not one | refused | status 401; Scrape.do's 401 |
| `url (missing)` | no url | refused | status 400; Scrape.do'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: 4 present, 0 empty, 10 absent.

| Field | State | Measured |
|---|---|---|
| `body` | present | every 200 page reply |
| `Scrape.do-Initial-Status-Code header` | absent | every 200 reply |
| `Scrape.do-Resolved-Url header` | absent | every 200 reply |
| `Scrape.do-Target-Url header` | absent | every 200 reply |
| `Scrape.do-Request-Cost header` | absent | every 200 reply |
| `Scrape.do-Remaining-Credits header` | absent | every 200 reply |
| `Scrape.do-Cookies header` | absent | every 200 reply |
| `content (returnJSON)` | present | the returnJSON reply |
| `frames (returnJSON)` | absent | the returnJSON reply |
| `networkRequests (returnJSON)` | absent | the returnJSON reply |
| `websocketResponses (returnJSON)` | absent | the returnJSON reply |
| `screenShots (returnJSON)` | absent | the returnJSON reply |
| `error error` | present | every refused call |
| `error message` | present | every refused call |
