High-Speed Stealth Scraping
Cloudflare Turnstile Auto-Bypass
Fast-Path HTTP Engine
Wire-level browser fingerprinting. Spoofs TLS ClientHello, H2/H3 frames, and TCP stack for maximum throughput.
Headless Browser Solver
Persistent Chrome process with tab pooling. Automatically detects and clicks Cloudflare Turnstile challenges.
Domain Cookie Store
In-memory cookie jar. Harvests cf_clearance and session cookies to skip subsequent challenges completely.
Dynamic Redirect Cache
Learns post-challenge destination hosts and routes repeat requests directly to final URLs on the fast path.
Stealth Request Studio
// Configure request parameters above and click "Send Request"...
<!-- Response body preview renders here -->
Domain Cache Explorer
Loading active domain cache entries...
API Reference
Primary endpoint for fetching content. Automatically routes through the fast-path or executes Cloudflare bypass via the persistent browser pool.
Authentication & Request Headers
| Header | Requirement | Type | Description |
|---|---|---|---|
| X-API-Key | Required | string | Secret API key configured in .env (e.g. anti_secret_key_123). 100% required for direct API endpoints (/fetch, /solve-turnstile, /cookies). Missing or invalid keys return 401 Unauthorized. |
| Authorization | Optional | string | Bearer token alternative: Bearer <your_api_key>. |
| Content-Type | Required | string | Must be set to application/json. |
Request Parameters (JSON Body)
| Field | Requirement | Type | Default | Description |
|---|---|---|---|---|
| url | Required | string | — | Target URL to fetch (e.g. https://example.com/protected-page). |
| method | Optional | string | "GET" | HTTP Method (GET, POST, PUT, DELETE,
PATCH). |
| headers | Optional | object | {} | Custom request headers merged into preset browser header order. |
| body | Optional | string | null | null | Raw request payload for POST/PUT requests. |
| user_agent | Optional | string | null | null (auto) | Custom User-Agent header string. When null, uses preset's authentic UA. |
| preset | Optional | string | "chrome-latest-windows" | Fingerprint profile (chrome-latest-windows, chrome-latest-linux,
firefox-latest). |
| proxy | Optional | string | null | null | Egress proxy: http://, https://, socks5:// or
socks5h://, credentials allowed (socks5://user:pass@host:port). Omit to use
direct or server WARP egress, or send "direct" to bypass it. Invalid
values return 422. See Proxy guide. |
| force_browser | Optional | boolean | false | Set true to skip fast-path and force headless browser execution. |
| force_http | Optional | boolean | false | Set true for HTTP only: never escalate to the browser; the raw response (even 403 or a challenge page) is returned as-is. Cannot be combined with force_browser. |
| follow_redirects | Optional | boolean | true | Set false to stop at the first response: returns 3xx status and redirect_url with target Location without fetching/downloading the target. Cannot be combined with click_selector or wait_for_selector. |
| cf_wait | Optional | float | 25.0 | Maximum wait seconds for Turnstile settlement in browser (early-exits immediately upon resolution). |
| session_id | Optional | string | null | null | Isolated session identifier (e.g. task-dl-1). Prevents cookie/session collisions between concurrent multi-step scraping tasks while sharing root-domain Cloudflare clearance. |
| wait_for_selector | Optional | string | null | null | CSS selector that must exist in live DOM before returning. Forces browser escalation if fast-path HTML lacks it (useful for client-rendered dynamic buttons). |
| click_selector | Optional | string | null | null | CSS selector to click once the page/Turnstile is resolved. Waits while the element is disabled, then reports what the click did: every navigation hop in redirect_chain (url, status, location) and the file's address if it started a download (the file itself is never fetched). Implies force_browser. |
| cookie_ttl | Optional | integer | 86400 | Cookie cache retention duration in seconds (default 24 hours). |
| inject_cookies | Optional | object | {} | Custom cookies to inject into this request before navigation. |
| cookie_allowlist | Optional | string[] | null | null (auto) | Allowed cookie names or glob/regex patterns (e.g.
["cf_*", "__cf*", "PHPSESSID", "token_*"]). Filters out junk/tracking cookies. |
| cookie_limit | Optional | integer | 35 | Maximum number of cookies allowed in request header before truncating oldest to prevent HTTP 400 buffer overflow. |
| selector | Optional | string | null | null | CSS selector to parse and extract from HTML on the server. |
| selector_all | Optional | boolean | false | Return all matching elements (true) or first match (false). |
| selector_attr | Optional | string | "text" | Attribute to extract: "text", "html", "href",
"src", etc. |
Response Schema
{
"status_code": 200,
"headers": { "content-type": "text/html; charset=UTF-8" },
"body": "<!DOCTYPE html>...",
"cookies": { "cf_clearance": "...", "session": "..." },
"url": "https://example.com/protected-page",
"protocol": "h2",
"extracted": null,
"meta": {
"via": "http", // "http" or "browser"
"request_type": "http_request", // "http_request" or "browser"
"preset": "chrome-latest-windows",
"cf_bypass_attempted": false,
"cache_hit": true, // True if served from cached session
"cookies_used": 2,
"body_truncated": false, // true: body skipped/cut (video, archive, over MAX_RESPONSE_MB)
"body_note": null // reason when body_truncated is true
}
}
Directly solves a Cloudflare Turnstile challenge and obtains a single-use token from the target widget's sitekey and origin siteurl. Uses route interception to avoid downloading third-party page assets.
Request Parameters (JSON Body)
| Field | Requirement | Type | Default | Description |
|---|---|---|---|---|
| sitekey | Required | string | — | Turnstile widget sitekey (0x...). Strictly validated against ^[A-Za-z0-9_-]{1,128}$. |
| siteurl | Required | string | — | Full URL of the origin domain the sitekey is authorized for (e.g. https://example.com/protected-form). |
| timeout | Optional | integer | 30 | Max seconds to wait for the browser worker to solve the widget (5 to 120s). Returns 504 on timeout. |
| proxy | Optional | string | null | null | Egress proxy for the solve session. Omit for direct/WARP connection. |
Response Schema
{
"solved": true,
"token": "0.m9V_sample_turnstile_response_token_...",
"elapsed": 2.45,
"siteurl": "https://example.com/protected-form",
"proxy": null
}
Feature Guides & Examples
The API includes a high-performance C-based HTML parser (selectolax Lexbor) on the backend.
Instead of downloading and parsing megabytes of HTML in your client code, you can pass CSS selectors
directly to receive cleanly extracted text or attributes.
selector: Any standard CSS selector (e.g."h1","table.torrent-table > tbody > tr","a.download-btn").selector_all: Set totrueto return an array of all matches; setfalseto return the first matching element.selector_attr: Choose"text"(default, trimmed innerText),"html"(outerHTML), or any HTML attribute name like"href","src","data-id".
{
"url": "https://example.com/items",
"selector": "a.download-btn",
"selector_all": true,
"selector_attr": "href"
}
The service includes a built-in Subdomain-Aware LRU In-Memory Cookie Store with Session Isolation & Pattern Allowlist Filtering. When a Cloudflare Turnstile challenge is solved, clearance tokens and sessions are stored automatically. Subsequent requests reuse these cookies to hit the fast-path (300ms) without opening a browser.
- Dual-Store Architecture (Zero LRU Pollution): Separates long-lived domain caches (64 slots, 24h TTL) from ephemeral scraping sessions (256 slots, 10m TTL). High-volume task session churn never evicts root domain clearances (such as
example.com). - Strict Session Isolation: When
session_idis provided (e.g."task-dl-1"), the request runs in an isolated sandbox. It never falls back to the root domain and never writes to root, preventing session cookie contamination and bot-score cross-linking via__cf_bm. - Synchronized Root Clearance: Non-session domain clearances write strictly
cf_clearanceto the root domain, atomically synchronizing matching User-Agent and proxy identities. When a challenge wall is encountered, rejected clearance is immediately purged from both the local session and root storage. cookie_allowlist: Array of allowed cookie names or glob/regex wildcard patterns (e.g.["cf_*", "__cf*", "*session*", "PHPSESSID"]). Non-essential tracking cookies and analytics are pruned automatically.cookie_limit: Upper bound on the number of cookies sent in request headers (default35, 3.5 KB max) to prevent HTTP 400 header overflow.inject_cookies: Inject custom session cookies before navigation. Injected cookies always bypass allowlist filters and take precedence.cookie_ttl: Cache duration in seconds for domain-level entries (default86400= 24 hours). Ephemeral sessions default to 10 minutes (600s).
{
"url": "https://new5.example.com/protected-page",
"session_id": "task-dl-42",
"cookie_allowlist": [
"cf_*",
"__cf*",
"*session*",
"PHPSESSID"
],
"cookie_limit": 25
}
The system keeps a persistent Chromium process per egress identity (direct, or one per
proxy), capped by MAX_BROWSERS. Incoming requests acquire a worker tab through a semaphore pool
(MAX_TABS) and clean up their isolated browser context on completion. Idle processes are
recycled after BROWSER_MAX_LIFETIME_SEC.
force_browser: Set totrueto skip the HTTP fast-path and drive Chrome directly. Use this for complex Single Page Apps (SPA) that require client-side JavaScript rendering.force_http: Set totrueto stay on the HTTP engine only. The browser is never started; a 403 or challenge page is returned as-is. Use this for POST/API calls where a 403 comes from the site itself, not Cloudflare.cf_wait: Maximum duration in seconds to wait for Cloudflare Turnstile to solve and redirect (default25.0s). Early-exits immediately as soon as the challenge is solved.- Dynamic Redirect Cache: When an origin domain redirects to a separate domain
post-challenge (e.g.
.com→.net), the API caches the destination so subsequent requests hit the final URL directly on the fast-path.
{
"url": "https://example.com/dynamic-spa",
"force_browser": true,
"cf_wait": 15.0
}
Fine-tune the wire-level network behavior, fingerprint profiles and User-Agent headers.
MAX_RESPONSE_MB (16), are never read into memory. You still
get status_code, headers and url (the final address after
redirects, ideal for download-gateway links) with an empty body, plus
meta.body_truncated: true and a meta.body_note reason.
user_agent: Pass a custom User-Agent string to override the preset's default. If omitted, the authentic preset User-Agent is sent.preset: Select from bundled browser fingerprint profiles:"chrome-latest-windows","chrome-latest-linux","firefox-latest".proxy: Route the request through an HTTP, HTTPS or SOCKS5 proxy. Each proxy gets its own browser process with matching timezone, locale and WebRTC IP.http_version: Force protocol version ("h1","h2","h3") or leave asnullfor auto-negotiation via ALPN.
{
"url": "https://example.com/api/data",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36",
"preset": "chrome-latest-windows",
"http_version": "h2",
"timeout": 45
}
Send any request through a residential, ISP or datacenter proxy. Cloudflare binds cf_clearance
to the IP that earned it and checks that the browser's timezone, language and WebRTC address agree with that
IP, so the API treats every proxy as a separate egress identity end to end.
Resolve
Request proxy > "direct" opt-out > server WARP egress.
Isolate
One Chromium process per proxy. SOCKS5 credentials are handed to Chromium itself.
Match
Timezone and locale come from the exit IP (GeoIP); WebRTC is pinned to that IP.
Cache
Cookies are namespaced per proxy, so a clearance is never replayed from another IP.
Supported formats
| Format | Notes |
|---|---|
http://user:pass@host:port | Most residential providers. Works on HTTP engine and browser. |
https://host:port | TLS connection to the proxy itself. |
socks5://user:pass@host:port | Authenticated SOCKS5, including special password chars (auto-encoded). |
socks5h://host:port | DNS resolved by the proxy (browser default for SOCKS5). |
"direct" | Explicitly bypass server egress for this request. |
Examples
{
"url": "https://example.com/protected",
"proxy": "http://user:pass@res.example.net:8000"
}
{
"url": "https://example.com/download/42",
"proxy": "socks5://user:pass@1.2.3.4:1080",
"session_id": "task-dl-42",
"force_browser": true
}
Failure handling
| Situation | Response |
|---|---|
| Malformed proxy (no scheme, no port, unsupported scheme) | 422, rejected before any network call; never falls back to direct connection. |
| Proxy refuses or drops the connection | status_code: 502 with a [PROXY-FAIL] log; no browser solve is wasted. |
| Any log, error or response body | Credentials are masked as socks5://***@host:port. |
Copy-pasteable code examples across languages and runtimes for stealth scraping and standalone Turnstile solving.
import httpx
# Send stealth request with API key
response = httpx.post(
"http://127.0.0.1:8000/fetch",
headers={"X-API-Key": "anti_secret_key_123"},
json={
"url": "https://example.com/protected-page",
"selector": "title",
"cf_wait": 25.0
},
timeout=30.0
)
data = response.json()
print("Status Code:", data["status_code"])
print("Engine Used:", data["meta"]["via"])
print("Extracted:", data["extracted"])
import os, httpx
response = httpx.post(
"http://127.0.0.1:8000/fetch",
headers={"X-API-Key": os.environ.get("ANTI_API_KEY", "anti_secret_key_123")},
json={
"url": "https://example.com/download-portal",
"proxy": "http://user:pass@residential.proxy:8080",
"session_id": "task-dl-42",
"click_selector": "button#start-download"
},
timeout=60.0
)
data = response.json()
print("Redirect chain:", data["redirect_chain"])