API reference

One endpoint. JSON in, data out.

Send a URL; get the page, structured data, or what your browser steps collected. Requests that hit an anti-bot wall are never charged.

Quick start

Create a key in the dashboard, then:

curl "https://stealthasf.bunnybag.space/v1/scrape" \
  -H "x-api-key: sasf_live_…" \
  -H "content-type: application/json" \
  -d '{"url": "https://quotes.toscrape.com/", "engine": "auto", "extract": "links"}'

Authenticate with x-api-key: <key> or Authorization: Bearer <key>. Browser requests can take up to ~2 minutes — set your client timeout to 180 s.

Request — POST /v1/scrape

fieldtypemeaning
urlstring, requiredhttp(s) URL, up to 2048 chars. Internal/private addresses are refused.
engineauto · http · browser · stealthauto (default) starts on plain HTTP and steps up to the stealth browser only when the site answers with an anti-bot wall; it also remembers sites that needed stealth. http: no browser. browser: real browser for JavaScript-built pages. stealth: anti-detect browser that clears Cloudflare Turnstile.
extractlinks · text · meta · emails · images · headings · tableReturn structured data instead of parsing HTML yourself.
stepsarray, up to 40Browser actions run in order on the page (see below). Forces a browser engine.
randomize{delays, motion, order}Human-like pauses, mouse and scroll between steps.
repeat, repeat_gap_msint, int (≤ 60000)Run the steps N times in one browser session with a pause between (e.g. read a price every 10 s). Stops after ~14 min.

Browser steps

Each step is a one-key object. Selectors start with css: or xpath:; append ::text or ::attr(href) to read text or an attribute.

stepexample
crawl{"crawl": {"links": "css:a.item", "next_page": "css:a.next", "fields": {"title": "css:h1::text"}, "max_items": 500}} — opens every detail link on each list page and extracts fields there, following next_page. One Cloudflare clearance for the whole crawl. Without links, extracts item_selector rows from the list pages.
scrape{"scrape": {"item_selector": "css:.row", "fields": {"name": "css:.name::text"}}}
click · hover · scroll · wait_for{"click": "css:button.more"}
type{"type": {"selector": "css:input[name=q]", "text": "boots"}}
press_key{"press_key": "Enter"}
goto · wait{"goto": "https://site/page/2"} · {"wait": 1500}
find_and_click{"find_and_click": {"text": "Load more"}} — scrolls until the text appears, then clicks.
collect_links{"collect_links": {"selector": "css:a.result"}}
capture{"capture": {"name": "price", "selector": "css:.price"}} — stores a value; use it later as {{price}}.
js_eval{"js_eval": {"name": "items", "code": "return (await fetch('/api/items')).json()"}} — runs in the cleared page with its cookies.
if_exists · try{"if_exists": {"selector": "css:.cookie-ok", "then": [{"click": "css:.cookie-ok"}]}} · {"try": {"steps": [...]}} (failures inside are ignored)

Response — 200

{
  "ok": true,
  "job_id": "cm…",
  "engine": "stealth",            // the tier that produced the result
  "status": 200,                  // the target's HTTP status
  "html": "<!doctype html>…",
  "data": { "kind": "table", "columns": [...], "rows": [[...]] },   // with "extract"
  "records": [ {"type": "crawl", "url": "…", "data": {...}} ],      // with "steps"
  "discovered_api": { "kind": "json_api", "url": "…", "method": "GET" },  // when the page called its own data API
  "usage": { "engine": "stealth", "bytes": 3145728, "proxy_mb": 3.1, "ms": 53210 },
  "credits_charged": 45,
  "balance": 249955
}

Errors

statusmeaningcharged
400Invalid body, URL, engine, extract or stepno
401Missing or invalid API keyno
402Not enough credits (balance included)no
422The site's anti-bot blocked the request (job_id, balance included)no
429Rate limit (120 requests/min per IP), or a free-plan account already has a request runningno
502The target could not be reached, or an engine errorno

Credits

whatcredits
http request1 (+1 per 2 MB of response)
browser request5 (+10 per MB of transfer beyond the first MB)
stealth request25 (+10 per MB of transfer beyond the first MB)
solved captcha+25
blocked request0

With engine: auto you pay only for the tier that succeeded. Images, video and fonts are not downloaded unless you ask for screenshots, so transfer stays small.