AntiBot & WAF Cheatsheet
Identify and unlock Akamai Bot Manager, DataDome, Kasada, Imperva Incapsula, Cloudflare, PerimeterX, and Fastly. TLS fingerprinting, header order, status codes, and BrowserSolver mode workflows with copy-ready snippets.
Mental model: identify, then unlock
Anti-bot walls fail scrapers on TLS fingerprint, header order, cookies, and IP long before parsers run. BrowserSolver Website modes own that session for you on allowlisted domains.
Two ways teams scrape protected sites.
DIY request client
Your code talks to the target with a browser-grade TLS stack,
keeps a clean cookie jar, and replays challenge posts.
Most “payload looks fine” failures are TLS / headers / IP / cookies.
BrowserSolver Website modes
One HTTP API: AntiBot (classify), then Crawler / Rendering / WebUnlocker.
Unlock playbooks run server-side on allowlisted hosts.
You parse HTML/JSON; you do not maintain sensor posts.Non-negotiables for any local browser-grade client.
1. Chrome TLS profile (latest available) + random extension order
2. HTTP/3 off when proxies do not support it
3. Exact browser header order (incl. HTTP/2 pseudo-headers)
4. Same UA + TLS + IP + hints for the whole flow
5. Sticky/session proxies (never rotate mid-challenge)
6. Clean cookie jar (no duplicate names / wrong domain)Which anti-bot is this? Quick routing
Identify the vendor from public response signals, then open the matching section or bypass guide.
Public identification cheat sheet.
Akamai Bot Manager
Cookies _abck + bm_sz; dynamic <script src="/xxxx/yyyy/..."> near body end
428 = SEC-CPT; 429 body with {"t":...} often SBSD
Imperva / Incapsula
reese84 cookie or x-d-token: reese84
/_Incapsula_Resource?SWJIYLWA=...: utmvc (___utmvc cookie)
"Pardon Our Interruption": reese84 dynamic (+ possible PoW)
DataDome
403 with inline var dd={...}; datadome cookie
i.js / rt:'i': interstitial; c.js / rt:'c': slider
tags = proactive /js telemetry (not a block page)
Kasada
429 HTML referencing ips.js; x-kpsdk-* / tkrm_alpekz_* cookies
x-is-human: Vercel BotID variant
Cloudflare
Managed Challenge / Turnstile; cf-ray; __cf_bm / cf_clearance
PerimeterX / HUMAN
px-cdn / client.perimeterx.net; _px* cookies; Access Denied walls
Fastly
Edge 403 / empty bodies before origin; CDN JS challenges; Fastly headersDetect vendor signals from HTML and headers
Use these heuristics in triage scripts before you call Website AntiBot at scale. Prefer AntiBot in production for named classification.
TypeScript heuristics over status, headers, and body.
type VendorGuess =
| "akamai" | "datadome" | "kasada" | "imperva"
| "cloudflare" | "perimeterx" | "fastly" | "unknown"
function guessVendor(status: number, headers: Headers, body: string): VendorGuess {
const setCookie = headers.get("set-cookie") ?? ""
const server = (headers.get("server") ?? "").toLowerCase()
const cfRay = headers.has("cf-ray")
if (/_abck=|bm_sz=/.test(setCookie) || /sec-cp-challenge/.test(body)) return "akamai"
if (status === 403 && /var\s+dd\s*=\s*\{/.test(body)) return "datadome"
if (status === 429 && /ips\.js|x-kpsdk-|tkrm_alpekz_/.test(body + setCookie)) return "kasada"
if (/reese84=|x-d-token|_Incapsula_Resource|Pardon Our Interruption/i.test(body + setCookie))
return "imperva"
if (cfRay || /__cf_bm=|cf_clearance=|cdn-cgi\/challenge/.test(body + setCookie))
return "cloudflare"
if (/perimeterx|px-cdn|_pxvid=|_pxhd=/i.test(body + setCookie)) return "perimeterx"
if (server.includes("fastly") || /x-fastly|fastly-/.test([...headers.keys()].join(" ")))
return "fastly"
return "unknown"
}Why stock HTTP clients fail anti-bot checks
requests, httpx, axios, node-fetch, and Go net/http expose non-browser TLS and header order. Prefer Website modes when you want BrowserSolver to own the session.
Fingerprint gaps that look like “vendor bugs”.
Bad (stock client fingerprint):
TLS ClientHello ≠ Chrome
Header order alphabetical or framework-default
sec-ch-ua / UA / platform version drift
Datacenter IP on a residential-only target
Good (browser-grade session):
Chrome TLS profile + random extension order
Wire-captured header order for that request class
Sticky IP for the whole challenge flow
Clean cookie jar (no duplicates / wrong domain)Chrome HTTP/2 pseudo-header order is stable. Firefox and Safari differ. Capture the wire order for the request you replay.
Chrome :method :authority :scheme :path
Firefox :method :path :authority :scheme
Safari :method :scheme :path :authority
Example Chrome navigation header order (illustrative):
:method, :authority, :scheme, :path,
sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform,
upgrade-insecure-requests, user-agent, accept,
sec-fetch-site, sec-fetch-mode, sec-fetch-user, sec-fetch-dest,
accept-encoding, accept-language, cookie, priorityTLS fingerprinting, header order, and client hints
Header order and HTTP/2 pseudo-headers are among the strongest bot signals. DevTools does not show true wire order.
Hard rules
Checklist before blaming a vendor challenge.
1. Header case: lowercase on HTTP/2, Title-Case on HTTP/1.1
2. Never set Content-Length manually (duplicate length = hard fail)
3. sec-ch-ua must match the UA Chrome major + GREASE brands
4. sec-ch-ua-platform must match the UA OS ("Windows" / "macOS")
5. If priority is last, cookie must sit immediately before it
6. accept-encoding for Chrome ≈ gzip, deflate, br, zstd
7. Disable HTTP/3 when proxies do not support it
8. Prefer sticky/session proxies; egress IP stays constant
9. Never hardcode sec-ch-ua-full-version-list (stale GREASE = block)
10. No DevTools “Disable cache” artifacts (cache-control + pragma no-cache)Chrome version coherence
UA, sec-ch-ua, and platform must agree.
Keep these three in lockstep on every request:
User-Agent … Chrome/<MAJOR>.…
sec-ch-ua "Google Chrome";v="<MAJOR>", "Chromium";v="<MAJOR>", "Not A(Brand";v="…"
sec-ch-ua-platform "Windows" | "macOS" (quoted, matching UA OS)
sec-ch-ua-mobile ?0 for desktop
Windows Chrome is the usual baseline; macOS Chrome is also common.
Bump MAJOR together. Never bump only the UA string.Cookie transport
Multiple cookie headers on HTTP/2 are normal Chrome behavior. On HTTP/1.1 cookies coalesce into one Cookie header.
HTTP/2 cookie: a=1
cookie: b=2 (correct; do not “fix”)
HTTP/1.1 Cookie: a=1; b=2
Jar bugs that look like WAF blocks:
- same cookie name twice with different values
- missing domain/path after Set-Cookie
- rotating IP mid-challenge while reusing cookiesIP, sticky proxies, and session consistency
Rotating IPs mid-challenge is one of the most common silent block causes. BrowserSolver Website modes manage egress for you; apply this when debugging a local client.
Proxy rules of thumb.
Use sticky / session proxies for the entire challenge + protected action
Never rotate mid-flow (sensor, then verify, then checkout)
Residential or mobile when datacenter IPs are scored to zero
One clean cookie jar per sticky IP / session
If DataDome slider shows t=bv: IP hard-ban; change sticky IP first
Re-probe with Website AntiBot after an IP pool changeAnti-bot HTTP status code reference
Quick map from status codes to challenge families.
Cross-vendor status codes you will see in the wild.
200 + challenge HTML Cloudflare / soft blocks / empty shells
403 + var dd={...} DataDome interstitial or slider
403 edge empty Fastly / generic CDN ACL
428 Akamai SEC-CPT (provider=crypto|behavioral|adaptive)
429 + ips.js Kasada
429 + {"t":"..."} Akamai SBSD hard block
429 / 503 rate shapes vendor rate limits (retry with backoff + sticky IP)
401 from api.* missing/wrong x-api-key on BrowserSolverAuthenticate BrowserSolver API calls
Every Website mode call uses your dashboard API key as x-api-key. Never ship the key in browser bundles.
Self-contained crawler probe (export the key once per shell).
export BROWSERSOLVER_API_KEY="your-key"
curl -sS "https://api.browsersolver.com/v1/website/crawler" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"https://example.com"}'Node helper you can paste above other TypeScript snippets on this page.
const API = "https://api.browsersolver.com/v1"
const KEY = process.env.BROWSERSOLVER_API_KEY!
async function websitePost(path: string, body: Record<string, unknown>) {
const res = await fetch(`${API}${path}`, {
method: "POST",
headers: {
"x-api-key": KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
if (!res.ok) {
throw new Error(`${path} ${res.status}: ${await res.text()}`)
}
return res.json()
}Python helper for the same pattern.
import os
import requests
API = "https://api.browsersolver.com/v1"
KEY = os.environ["BROWSERSOLVER_API_KEY"]
def website_post(path: str, body: dict):
r = requests.post(
f"{API}{path}",
headers={"x-api-key": KEY, "Content-Type": "application/json"},
json=body,
timeout=120,
)
r.raise_for_status()
return r.json()Bypass Akamai Bot Manager: signals and status codes
Public signals for Akamai Bot Manager: _abck sensors, SEC-CPT 428, SBSD 429, and optional pixel. Unlock on allowlisted domains with Website WebUnlocker.
Identify Akamai
Cookies, scripts, and challenge families.
Cookies: _abck, bm_sz (sec_cpt on SEC-CPT flows)
Script: dynamic <script src="/xxxx/yyyy/..."> near end of body
(path is per-response; never hardcode)
UA: Chrome Windows/macOS expected by sensor flows
Status codes:
200 + sensor script : standard _abck sensor flow
428 : SEC-CPT ({"sec-cp-challenge":"true","provider":…})
429 + {"t":…} : SBSD (state-based scraping detection)
Pixel script present : optional; presence ≠ enforcement
_abck validity (site-dependent):
Often contains ~0~ when ready; some sites need exactly 3 sensor posts
After a protected action, cookie may invalidate (~0~-1~-1): re-sensor
If still invalid after 3 sensors: TLS/headers/IP, not “more sensors”SEC-CPT providers (HTTP 428)
provider selects the challenge family. Success: sec_cpt contains ~3~.
crypto mandatory wait (chlg_duration) + PoW, then /_sec/verify?provider=crypto
behavioral 1-3 sensor posts + dynamic verify_url
adaptive wait + PoW (answers count), then behavioral sensors
verify on static /_sec/cp_challenge/verify
Keep sec-ch-ua / mobile / platform coherent for the whole solve.
SEC-CPT can appear on first load or mid-session on an API call.SBSD modes
Three shapes of State Based Scraping Detection.
(a) Passive: page loads; SBSD script has v UUID, no t
Post index 0 then index 1 to the script path
(b) Hard challenge: blocking page with v and t in the script URL
Single payload POST to /[path]?t=[t]
(c) 429 block: protected call returns {"t":"..."} only
Reuse stored path + UUID + script from an earlier solve
POST fresh payload to /[path]?t=<token>, then retry
Always store path/UUID/script before you start protected traffic.BrowserSolver path
Self-contained: probe then unlock (inspect JSON fields in docs).
export BROWSERSOLVER_API_KEY="your-key"
URL='https://shop.example.com/product/1'
curl -sS "https://api.browsersolver.com/v1/website/antibot" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"query\":\"$URL\"}"
curl -sS "https://api.browsersolver.com/v1/website/webunlocker" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"query\":\"$URL\"}"Bypass DataDome: interstitial, slider, and tags
DataDome is aggressive on retail and ecommerce catalogs. Hard IP bans (t=bv) need a new sticky residential IP, not another solve.
Identify DataDome
Block page vs proactive tags.
HTTP 403 with inline `var dd={...}`
Keep from dd: cid, hsh, s, b/t/e (type-dependent) + blocked URL as referer
Cookie: datadome=... on the 403
Challenge types:
rt:'i' + https://ct.captcha-delivery.com/i.js: interstitial
rt:'c' + https://ct.captcha-delivery.com/c.js: slider (captcha)
tags: NOT a block page; proactive POST to the site's /js endpoint
(often type=ch then type=le) to raise trust
Hard IP ban:
slider field t=bv: proxy hard-blocked; solving will not help
Rotate sticky residential / mobile IP before retryingBrowserSolver path
Self-contained unlock call.
export BROWSERSOLVER_API_KEY="your-key"
curl -sS "https://api.browsersolver.com/v1/website/webunlocker" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"https://shop.example.com/product/sku-42"}'Bypass Kasada and Vercel BotID
Kasada surfaces as 429 + ips.js. Vercel BotID adds x-is-human. Prefer WebUnlocker on allowlisted domains instead of hand-rolling POW.
Public identification checklist.
HTTP 429 HTML referencing ips.js
Headers/cookies: x-kpsdk-*, tkrm_alpekz_s1.3, tkrm_alpekz_s1.3-ssn
Script path with two GUID segments, e.g.
/149e9513-.../2d206a39-.../{ips.js|fp|tl|mfc}
Common flows:
Flow 1: 429 on homepage, then GET ips.js, then POST /tl, then reload
Flow 2: /fp fingerprint endpoint, then same ips.js /tl path
(referer = /fp URL); protected calls may need fresh x-kpsdk-cd
Vercel BotID:
x-is-human header; script often named c.js
Stale token or IP change: regenerate after re-fetching c.js
Payload bodies are large: usually gzip/br/zstd + content-encodingSelf-contained unlock call.
export BROWSERSOLVER_API_KEY="your-key"
curl -sS "https://api.browsersolver.com/v1/website/webunlocker" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"https://shop.example.com/collections/sneakers"}'Bypass Imperva Incapsula: reese84 and utmvc
Distinguish reese84 vs utmvc before you scale unlock traffic.
Which Imperva flavor?
reese84
Cookie named reese84 and/or x-d-token header
Script path often static per site (POSTs with ?d=)
Token JSON includes renewInSec: renew before expiry
reese84 dynamic
"Pardon Our Interruption" page
May require a PoW step before the token is accepted
utmvc
Script like /_Incapsula_Resource?SWJIYLWA=...
Cookie name is ___utmvc (three underscores)
Large body: compress (gzip/br/zstd)
Also watch for Incapsula captcha blocks (hCaptcha / Geetest)
after sensors when trust is still lowSelf-contained unlock call.
export BROWSERSOLVER_API_KEY="your-key"
curl -sS "https://api.browsersolver.com/v1/website/webunlocker" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"https://retail.example.com/catalog"}'Bypass Cloudflare Challenge Pages and Turnstile
Challenge Pages, Turnstile, and Bot Fight Mode are the usual walls. Escalate only after Crawler or Rendering already failed.
Common Cloudflare block signals.
Managed Challenge / Turnstile interstitial instead of product HTML
cf-ray response header
__cf_bm / cf_clearance cookies after a successful browser challenge
Bot Fight Mode / Under Attack soft blocks (empty or cookie-gated body)
Soft “200 OK” pages that omit the data you need
cdn-cgi/challenge paths in HTML or network waterfallsSelf-contained mode ladder with curl.
export BROWSERSOLVER_API_KEY="your-key"
URL='https://shop.example.com/collections/all'
# 1) cheapest
curl -sS -o /tmp/out.html -w "%{http_code}" "https://api.browsersolver.com/v1/website/crawler" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" -d "{\"query\":\"$URL\"}"
# 2) JS-heavy but reachable: /website/rendering
# 3) challenge wall on allowlisted host: /website/webunlockerBypass PerimeterX / HUMAN bot defense
PerimeterX (HUMAN) mixes device fingerprinting with edge scores. Confirm with AntiBot, unlock with WebUnlocker on allowlisted hosts.
Signals to watch for.
Scripts/hosts referencing px-cdn, client.perimeterx.net, or human security
Cookies: _px*, _pxhd, _pxvid (names vary by integration)
Block pages mentioning Access Denied with PX/HUMAN branding
Often paired with App / bot score on XHR after first paint
First paint can succeed while XHR data calls fail with PX scoresSelf-contained AntiBot probe.
export BROWSERSOLVER_API_KEY="your-key"
curl -sS "https://api.browsersolver.com/v1/website/antibot" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"https://store.example.com/"}'Bypass Fastly Bot Management and edge WAF
Fastly often protects high-traffic catalogs at the CDN edge before origin HTML. Unlock on allowlisted hosts with Website WebUnlocker.
Common Fastly edge signals.
Edge 403 or empty bodies before origin content
JS challenges served from the CDN
Rate and ACL denials on catalog paths
Server / via headers mentioning Fastly
x-fastly-* or Fastly-specific cache headers on blocksSelf-contained unlock call.
export BROWSERSOLVER_API_KEY="your-key"
curl -sS "https://api.browsersolver.com/v1/website/webunlocker" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"https://catalog.example.com/"}'Mode ladder: AntiBot, Crawler, Rendering, Unlock
Burn the cheapest mode that works. AntiBot is for classification; WebUnlocker is for allowlisted vendor-hardened hosts.
Decision matrix.
Website AntiBot : name vendor / challenge / fingerprint gap
Website Crawler : static HTML & JSON APIs (cheapest)
Website Rendering : JS-heavy pages you can already reach
Website WebUnlocker: Cloudflare / DataDome / Akamai / PX / Kasada /
Imperva / Fastly on allowlisted domains
Rules:
- Do not start on WebUnlocker for every URL
- Re-probe with AntiBot when overnight pass rates collapse
- Confirm domain support before production unlock volume
- Failed unlock retries after exhaustion are not billed (see product docs)Website AntiBot probe before you burn unlock credits
One URL per call. Inspect the JSON response in the docs for vendor / challenge / mode hints, then route traffic.
Self-contained probe (print raw JSON).
export BROWSERSOLVER_API_KEY="your-key"
curl -sS "https://api.browsersolver.com/v1/website/antibot" \
-H "x-api-key: $BROWSERSOLVER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"https://example.com"}'TypeScript wrapper (fields follow current API docs).
const API = "https://api.browsersolver.com/v1"
const KEY = process.env.BROWSERSOLVER_API_KEY!
const res = await fetch(`${API}/website/antibot`, {
method: "POST",
headers: { "x-api-key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({ query: process.argv[2] ?? "https://example.com" }),
})
console.log(await res.json())Unlock once, parse forever
WebUnlocker returns scrape-ready markup with the same redirect / raw-source controls as Crawler. Keep parsers on one response shape (see current docs).
Self-contained unlock + Cheerio parse (adapt body field to your docs).
import * as cheerio from "cheerio"
const API = "https://api.browsersolver.com/v1"
const KEY = process.env.BROWSERSOLVER_API_KEY!
const res = await fetch(`${API}/website/webunlocker`, {
method: "POST",
headers: { "x-api-key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({ query: "https://shop.example.com/p/sku-1" }),
})
const page = await res.json()
const html = typeof page === "string" ? page : String(page.html ?? page.body ?? page)
const $ = cheerio.load(html)
console.log({ title: $("h1").first().text().trim() })Production pipeline pattern for protected catalogs
Classify once per host, cache the mode, unlock only when needed.
Host-to-mode cache sketch.
type Mode = "crawler" | "rendering" | "webunlocker"
const modeByHost = new Map<string, Mode>()
async function fetchHtml(url: string): Promise<unknown> {
const host = new URL(url).host
const mode = modeByHost.get(host) ?? "crawler"
const path = `/website/${mode}`
try {
return await websitePost(path, { query: url })
} catch {
if (mode === "crawler") {
modeByHost.set(host, "rendering")
return fetchHtml(url)
}
if (mode === "rendering") {
modeByHost.set(host, "webunlocker")
return fetchHtml(url)
}
// Optional: website/antibot once, then force webunlocker if allowlisted
throw new Error(`exhausted modes for ${host}`)
}
}
// websitePost: copy from “Authenticate BrowserSolver API calls”Vendor unlock guides on browsersolver.com
Deep-dives for each WAF playbook. Use them when pitching coverage or onboarding a new domain.
Canonical product routes.
/products/website-antibot
/products/website-webunlocker
/products/website-crawler
/products/website-rendering
/products/website-technology : stack signals alongside AntiBotTriage: first five questions when scraping is blocked
Work top-down. Cross-cutting session bugs are far more common than “wrong vendor playbook”.
Ask these before opening a support ticket.
1. Does AntiBot return a named vendor, or is the URL unreachable?
2. Did Crawler / Rendering already fail on the same URL?
3. Is the host on the WebUnlocker allowlist (or did support enable it)?
4. Are you reusing a sticky session/IP for the whole job, or rotating mid-flow?
5. Is the failure a challenge wall, empty soft-block, rate limit, or 5xx?
If 2–4 are “no / unsure”, fix routing before blaming unlock.Symptom, cause, and fix for anti-bot blocks
Cross-cutting matrix for scrapers and local clients.
Symptom Likely cause Fix
Works locally, fails in prod rotating proxy / IP drift sticky session proxies
Intermittent blocks dirty cookie jar or mid-flow rotate one jar + one IP per session
Blocked immediately DC IP or UA/sec-ch-ua mismatch residential + coherent UA
DataDome rejects despite UA hardcoded full-version-list do not hardcode client hints
Unlock returns challenge HTML domain not allowlisted / wrong mode confirm coverage; re-probe
Crawler empty, browser works JS-rendered content Website Rendering
Rendering challenge wall vendor bot manager Website WebUnlocker
Pass rate drops overnight vendor changed protection AntiBot re-probe + mode bump
401 / missing key x-api-key absent or wrong set header from dashboard keyVendor-shaped symptoms (when you still debug locally).
Akamai
_abck never valid after 3 sensors: TLS/headers/IP, not “more sensors”
428 mid-session: SEC-CPT; keep hints coherent; honor chlg_duration waits
429 {"t":…}: SBSD; reuse path/UUID/script, post a fresh payload
DataDome
t=bv on slider: IP hard-ban; change sticky IP
Still blocked after interstitial/slider: tags trust may be low
Imperva
reese84 persists: token/IP issue; renew before renewInSec
utmvc rejected: cookie must be ___utmvc; compress large bodies
Kasada
429 loops: stale x-kpsdk-cd POW reused across requests
x-is-human rejected: re-fetch BotID c.js after IP/UA change
Fastly
Edge 403 with empty body: unlock / allowlist before origin parsersWhat to capture when debugging WAF blocks
BrowserSolver owns the unlock session; still keep a small HAR or response dump when filing tickets. Prefer wire captures when you debug a local TLS client: HAR alone lacks true header order and TLS fingerprint.
Minimum evidence pack.
Include:
- target URL + timestamp (UTC)
- AntiBot JSON (vendor / challenge / mode hints)
- mode used (crawler | rendering | webunlocker)
- HTTP status + first 2–4 KB of body (redact PII)
- response headers: cf-ray, set-cookie names (not values), server
- whether the domain is allowlisted
- for local clients: TLS profile id + header-order list from a wire proxy
Skip:
- full cookie values in public channels
- API keys
- unrelated analytics / ad noiseRedact helper before pasting into Slack/email.
function redact(html: string, max = 4000) {
return html
.replace(/datadome=[^;\s]+/gi, "datadome=REDACTED")
.replace(/_abck=[^;\s]+/gi, "_abck=REDACTED")
.replace(/reese84=[^;\s]+/gi, "reese84=REDACTED")
.replace(/___utmvc=[^;\s]+/gi, "___utmvc=REDACTED")
.replace(/cf_clearance=[^;\s]+/gi, "cf_clearance=REDACTED")
.slice(0, max)
}DIY TLS client vs BrowserSolver Website modes
Use this when deciding whether to maintain a local browser-grade client or route through Website AntiBot / WebUnlocker.
When to stay on BrowserSolver modes.
Use Website AntiBot + WebUnlocker when:
- you want one HTTP API for crawl / render / unlock
- you do not want to maintain TLS clients + challenge posts
- the domain is (or can be) allowlisted
Use a local browser-grade client only when:
- you are researching a new host before requesting allowlist
- you need interactive debugging of a single challenge flow
Do not expect Website modes to return raw sensor payloads.
Do not post DIY challenge bodies through Website Crawler / Unlock.