---
title: Tiered Execution
description: How TRAWL escalates through four tiers - from a plain fetch to a residential proxy solve.
---
# Tiered Execution
Ordinary scrape requests use a four-tier waterfall, subject to request limits and proxy policy.
Each tier is tried only when earlier work fails or is skipped. Named browser sessions use their
own retained context and bypass the shared clearance cache.
```
Request
│
▼
Tier 1: HTTP Fetch ───────── success ──→ return
│ optional cached clearance + saved browser identity
│ blocked / needs-js
▼
Tier 2: Cached Session ────── success ──→ refresh cache, return
│ blocked / cache miss
▼
Tier 3: Fresh Challenge ───── success ──→ cache cookies, return
│ IP flagged
▼
Tier 4: Residential Proxy ─── success ──→ cache cookies, return
│ failed
▼
error
```
## Tier 1 - Plain HTTP Fetch
The cheapest tier. Uses Bun's native `fetch()` by default, with Firefox navigation
headers. Set [`TIER1_TRANSPORT=wreq`](/getting-started/configuration#tier1-transport)
to opt into Firefox TLS/HTTP2 impersonation. Its native profile supplies the fresh
HTTP User-Agent; accepted clearance replays keep the saved browser identity.
The default Bun header set is:
```
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br, zstd
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Priority: u=0, i
```
**Succeeds for:** sites that serve the requested content without a browser challenge.
Eligible repeat requests send saved Cloudflare or Anubis clearance cookies and the browser's
User-Agent rather than making an unauthenticated probe. The response is fetched again, not
served from a body cache. Rejected clearance falls back to the browser tiers. This requires
a direct GET/HEAD request, verified TLS and matching origin provenance; see
[Session Cache](/architecture/session-cache#automatic-http-clearance-reuse) for eligibility and fallback.
**Escalates for:** recognized Cloudflare, Akamai, or Imperva challenge responses and blocked status codes such as 403 or 429. Detection uses provider-specific headers and HTML markers.
**Skip with:** `skipHttp: true` in the request body, or deployment-wide `SCRAPE_MIN_TIER=2`.
Use `maxTier: 1` to cap execution at Tier 1 instead.
## Tier 2 - Cached Browser Session
Reads `session:v2:{hostname}` from the configured Redis or memory cache. If found, injects the saved
cookies into a pooled Firefox context and navigates. Proxy-bound sessions use an isolated temporary
context on the same browser through their original configured proxy. This path also handles clearance that the
HTTP tier cannot reuse. When the target accepts the cached cookies and browser identity, the
site loads without a fresh challenge solve.
**Succeeds for:** previously solved domains whose cached session is still accepted.
**Fails for:** expired or rejected sessions. On failure, TRAWL invalidates the cached session and escalates to Tier 3.
## Tier 3 - Fresh Challenge Solve
Acquires a browser from the pool (or waits up to `BROWSER_ACQUIRE_TIMEOUT_MS`, default 15s,
within the remaining request budget), creates a fresh Camoufox context and navigates. Ordinary
solves start without cached cookies; explicitly imported cookies use an isolated context and
do not enter the shared cache. TRAWL identifies the wall and runs the matching provider flow
until the protected page replaces it or the request deadline expires.
On success:
- Extracts cookies from the page context.
- Saves eligible shared session state when cookies are available, using the configured cache
driver and `REDIS_SESSION_TTL_SECONDS`. Direct, TLS-verified GET/HEAD visits with matching
requested and final origins can record `httpOrigin` for later HTTP reuse.
- Returns the HTML and cookies to the caller.
Uses [Camoufox](https://github.com/daijro/camoufox) - Firefox with fingerprint patching at the C++/Juggler level to reduce common automation signals. Success still depends on the target's challenge variant, IP reputation, and upstream network conditions.
### Cloudflare recovery and fallback
A `cf_clearance` cookie alone does not confirm page access. The Cloudflare waiter still
requires two readable observations without an active challenge. If clearance is present but
the redirect has not completed after five seconds, TRAWL attempts one recovery navigation.
An unchanged clearance and a wall that persists for another five seconds stop that attempt.
A newly issued clearance token receives a fresh grace period without repeating the navigation.
When Tier 4 is allowed and a configured residential proxy is outside cooldown, ordinary
requests reserve one third of the remaining time, capped at 30 seconds, for escalation.
This cutoff applies only to Tier 3 Cloudflare waiting and is shared across datacenter retries.
Other provider flows and page readiness retain the request budget. Requests with an explicit
proxy, or without an available residential fallback, do not reserve this time.
### Embedded CAPTCHA widgets
Detected access challenges must clear before content is returned. After the page loads,
`solveEmbeddedCaptchas` controls attempts on embedded form widgets: native `/scrape` and MCP
`scrape` default to `true`; FlareSolverr-compatible `/v1` defaults to `false`. Set it to `false`
when only page content is needed, or `true` to request widget attempts. These are best-effort
attempts within the request deadline, reserving two seconds for document capture.
Only verified widget solutions appear in `captchasSolved`. An iframe can remain mounted after
completion, so iframe disappearance is not used as proof of success. See the
[native API](/api-reference/native-api#embedded-captcha-widgets) for request semantics.
| Provider | Attempted path | Confirmation |
| ---------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------- |
| Turnstile | Existing shadow-DOM or frame checkbox interaction | Widget response token |
| reCAPTCHA v2 | Checkbox or audio challenge | Existing response/checked-state checks |
| hCaptcha | Checkbox auto-pass; audio where the site offers it | Checked checkbox state; image grids remain unsupported |
| GeeTest slide | Piece texture matching with screenshot fallback; up to three recalculated puzzles | Explicit verified widget state, never just a closed popup |
| ALTCHA | Native component verification or checkbox | Verified state/response |
| Friendly Captcha | Native component or provider-frame start | Completed response |
| CAP | Native component or its shadow control | Component response token |
CAP uses the installed widget's own PoW implementation, browser proxy and outbound policy. It adds no solver dependency or external paid service. Component readiness and offscreen controls are handled within the request budget. Visible CAP widgets are solved sequentially within the shared budget, and all must have a response before completion is reported. The solver does not submit the surrounding form.
A widget's client-side response is not proof that the target application's server accepted a subsequent business request. Targets with unsupported puzzles or IP restrictions can still refuse access.
### Akamai Bot Manager challenges
Tier 3 and Tier 4 detect Akamai's `sec-cpt` / SBSD behavioral interstitials. The Akamai flow handles supported press-and-hold widgets, stops the gesture when the main document navigates, waits for a valid `_abck` sensor cookie, and revisits the original URL when the interstitial does not reload automatically. Sensor-only pages receive bounded pointer movement. Recovery stays within the remaining request budget.
Akamai configurations vary between properties and change over time. TRAWL treats a persistent interstitial as blocked and can escalate to Tier 4 when a residential proxy is configured.
### Imperva/Incapsula challenges
Tier 3 and Tier 4 also detect and resolve supported Imperva/Incapsula WAF challenges. Imperva's `reese84` (current) / `___utmvc` (legacy) sensor cookies are produced by an obfuscated in-page JS challenge. TRAWL detects the response with `packages/tiers/src/utils/detect.ts` and waits for the sensor cookie through `packages/tiers/src/utils/impervaWait.ts`.
Detection checks active challenge frames and sensor bootstrap shells. Cookie names in article text, inactive HTML examples, and ordinary Imperva CDN headers alone do not trigger browser escalation.
**Caveat:** unlike Turnstile, Imperva's script sometimes layers in TLS/JA3 and behavioral checks beyond plain cookie generation, and its obfuscation changes periodically - success isn't guaranteed at the same rate as Cloudflare. Some Imperva deployments also show a visible interactive CAPTCHA widget (distinct from hCaptcha/reCAPTCHA) instead of the passive sensor-only path; that variant isn't solved yet.
### DataDome challenges
Tier 3 and Tier 4 detect the three DataDome responses. All of them arrive through
`captcha-delivery.com`:
| Response | Marker | TRAWL action |
| -------------- | ---------------------------- | ------------------------------------------------------------------------------------- |
| Device Check | `i.js` script, `dd.rt = 'i'` | Runs `packages/tiers/src/utils/datadomeWait.ts` and waits for a new `datadome` cookie |
| Slider CAPTCHA | `c.js` script, `dd.rt = 'c'` | Reports `datadome-captcha-required`. No solver yet |
| Hard block | `t=bv` on the challenge URL | Reports the IP as blocked and escalates to Tier 4 |
The block-only `x-dd-b` response header lets the MITM proxy escalate before the body arrives.
Some DataDome Device Check deployments require a browser running behind a display. TRAWL
sends detected DataDome work to an opt-in headful pool running behind Xvfb.
Tier 1 can select the pool before browser acquisition. If a later tier detects DataDome,
the orchestrator replaces the headless lease and retries that tier once. The optional pool
is warmed during startup.
The sub-pool is off by default: set `BROWSER_HEADFUL_POOL_SIZE=1` to scrape DataDome
targets. See [Configuration](/getting-started/configuration).
## Tier 4 - Residential Proxy Escalation
Same as Tier 3 but launches the browser with `RESIDENTIAL_PROXY_URL` set as the proxy. Only triggered when:
1. `RESIDENTIAL_PROXY_URL` is configured
2. Tier 3 failed (usually because the datacenter IP is flagged)
If `RESIDENTIAL_PROXY_URL` is not set, Tier 4 is skipped entirely and the request returns an error after Tier 3 fails.
## Tier selection
The orchestrator (`packages/tiers/src/orchestrator.ts`) controls escalation. You can limit it via `ScrapeRequest.maxTier`:
```json
{ "url": "...", "maxTier": 2 }
```
This runs Tier 1, then Tier 2, then returns an error if both fail - never launching a fresh browser solve.
## Reading tier timings
| Tier | Work performed | Browser used |
| ---- | ----------------------------------------------------- | -------------- |
| 1 | HTTP fetch, optionally with eligible cached clearance | No |
| 2 | Navigate with cached cookies and browser identity | Yes, warm pool |
| 3 | Fresh context and challenge solving | Yes, warm pool |
| 4 | Browser solve through the configured proxy | Yes, warm pool |
Latency depends on the target, network, clearance acceptance and challenge variant. A fast
Tier 1 repeat is not a measurement of first-visit challenge solving. See
[Performance & Benchmarks](/getting-started/performance) for recorded first/repeat results
and CPU/memory measurements instead of fixed per-tier timing estimates.
### Anubis proof of work
Anubis uses the site's own JavaScript for proof of work. TRAWL polls a small browser DOM summary every 300 ms, respects the remaining request budget, and rejects denial pages or unresolved verification endpoints. Supported cached authentication cookies can enable direct HTTP reuse; rejected clearance returns to the browser tiers. PoW CPU and memory usage depend on the target policy and browser worker count; a 1 GiB limit is not sufficient for every public deployment.
A closed Anubis browser page may be retried once for GET or HEAD within the original timeout. If the container cgroup reports a new OOM kill, TRAWL stops instead of repeating the expensive solve. On systems without cgroup counters, recovery remains limited to one retry. POST requests are never replayed.
## Optional paid fallback
A deployment can enable the [external CAPTCHA solver](/getting-started/configuration#optional-external-captcha-solver).
It runs after supported built-in solvers inside browser tiers 2-4, using the same
page and the remaining request deadline. It is not a fifth tier. One shared
allowance limits paid task creation across all tiers and proxy attempts.
Automatic fallback handles declarative reCAPTCHA v2/Enterprise, standalone
Turnstile and supported Turnstile-based Cloudflare Challenge Pages. For the latter,
an opt-in observer installed before navigation captures document-bound render
parameters and the original callback. Local solving runs first; the provider
answer must match the browser identity and the wall must clear before success.
Other documented API v2 task types use hostname-bound profiles with
explicit inputs, delivery and a verification selector. A detected SDK marker
alone never creates a paid task. Profile-enabled hostnames escalate HTTP HTML
responses to a browser, and WAF waiters can use a profile after local resolution
fails. Existing local handling is preserved when the service is disabled.