cloudflare challenges · interstitial pages · session clearance

Cloudflare Challenge Solver

The full-page interstitial Cloudflare serves before it will show you the site is a Cloudflare challenge page. SolveGate clears it through the same endpoint, with gate=waf.

—provider average
—success rate
$0.40per 1,000 solves
$0.075per 1,000 at volume

// failed solves are never billed · credits never expire · first 1,000 solves free

// statistics use cached, retained solve records, including sandbox responses. Provider averages exclude queue wait and previous retries; request times vary.

What a Cloudflare challenge page is

A WAF challenge page is not the inline widget. Cloudflare serves it in place of the page, holds the request, and only proxies through once the challenge clears. It is what sits behind most "Just a moment…" screens and many 403s on Cloudflare-fronted origins.

Captcha challenge

The interstitial that renders a Turnstile widget and blocks the page until it is satisfied.

Interstitial page

The scripted hold with no visible widget, issued and verified before the origin is reached.

Session clearance

A valid clearance cookie can cover later requests from the same visitor, subject to challenge level and session checks.

Use gate=waf for a Cloudflare challenge page. The current API requires sitekey as well: send the non-empty placeholder waf, which this provider does not use. Supply the target URL and the proxy you will use for the same session.

The inline Turnstile widget embedded in a form is a different gate. It has its own page.

How to tell you are behind a Cloudflare challenge

Check the response header to identify a Cloudflare challenge page. The status and body are useful clues, but are not conclusive alone:

SignalWhat to look for
The statusA 403 where you expected content, or a 200 whose body is a holding page rather than the site.
The headercf-mitigated: challenge on the response. This is the unambiguous one.
The bodyScript or form names beginning __cf_chl_, and the phrase "Just a moment" or "Checking your browser" in place of the page.
The cookiecf_clearance can be issued after a challenge or through pre-clearance. Its absence alone does not identify the cause of a blocked request.

If the site itself renders and only one form is gated, you are looking at the embedded widget instead, which is the turnstile gate.

How to solve a Cloudflare challenge, in three steps

  1. Identify the challenge page. Check for cf-mitigated: challenge. Use its URL and your session's proxy; send sitekey: "waf" for the current API's required placeholder.
  2. POST it to /v1/solve. Send the gate, the sitekey and the URL the challenge sits on, authenticated with your secret key.
  3. Apply the clearance payload. Decode the JSON string in token, then apply its cookies and headers to the same target session. The string itself is not a cookie value.
request
curl https://api.solvegate.io/v1/solve \
  -H "Authorization: Bearer sk_live_•••" \
  -d gate=waf \
  -d sitekey=waf \
  -d url=https://app.example.com
200 · gate cleared
{
  "id":       "slv_8Kd2…aF9",
  "status":   "solved",
  "gate":     "waf",
  "token":    "{\"cookies\":{\"cf_clearance\":\"example-clearance\"},\"set_cookies\":[],\"headers\":{\"user-agent\":\"example-agent\"},\"attributes\":{},\"cf_rt\":\"\"}",
  "solve_ms": 980,
  "billed":   true
}

Parameters

FieldTypeDescription
gatestringRequired. Which challenge stands in the way — turnstile or waf.
sitekeystringRequired. Actual widget sitekey for turnstile; use the non-empty placeholder waf for the waf gate.
urlstringRequired. The page the challenge is on. The token is issued for that origin.
actionstringOptional. The Turnstile action value, when the site sets one.
asyncbooleanOptional. Return a pending solve immediately and poll GET /v1/solve/{id} instead of holding the connection.
proxystringOptional. Solve through your own egress IP instead of ours.

The async form

The call above waits for the solve result until the HTTP wait limit. Send async: true and it returns immediately with a pending solve instead, which you poll. Use it when you are solving many gates at once and would rather not hold a connection per solve.

POST /v1/solve · async
{
  "id":       "slv_8Kd2…aF9",
  "status":   "pending",
  "token":    null,
  "solve_ms": null
}
GET /v1/solve/{id} · solved
{
  "id":         "slv_8Kd2…aF9",
  "status":     "solved",
  "token":      "{\"cookies\":{\"cf_clearance\":\"example-clearance\"},\"set_cookies\":[],\"headers\":{\"user-agent\":\"example-agent\"},\"attributes\":{},\"cf_rt\":\"\"}",
  "solve_ms":   980,
  "expires_at": 1787620000,
  "billed":     true
}

Poll the id until status leaves pending. Retrieval is free and never re-bills the solve, so polling costs nothing but the request.

Send a unique Idempotency-Key for each logical solve and reuse it with the same body after a lost response. An HTTP timeout does not cancel queued work; retrying without the original key can create another billable solve. See the solve reference.

What comes back

FieldTypeDescription
idstringThe solve, prefixed slv_. Pass it to GET /v1/solve/{id} to retrieve.
statusstringsolved, pending or failed.
gatestringWhich gate was cleared — turnstile or waf.
tokenstringTurnstile token or JSON-encoded WAF cookies/headers. Null until status is solved.
solve_msintegerFinal provider attempt duration; excludes queue wait, previous retries and persistence.
expires_atintegerSolveGate's estimated use-by timestamp; not an expiry confirmed by Cloudflare.
modestringlive for a real solve, sandbox for the deterministic test response an sk_test_ key returns.
billedbooleanWhether this solve consumed a credit. Only successful solves are billed.
meterstringcredits, pass or sandbox — which meter paid for it.
error_codestringNull unless status is failed. See the table below.
error_messagestringHuman-readable explanation of error_code.

When it fails

Failures are typed, and the ones that are our fault or the network's are not billed. That is the column worth reading: a failure mode that costs money is one you have to engineer around.

StatusCodeMeaning
401invalid_keyMissing or revoked API key.
402balance_emptyOut of credit. Top up from the dashboard.
402pass_expiredThe unlimited pass this key is attached to has ended. Expiry is a hard stop — we never quietly spend your credit balance instead.
403forbidden_targetThis target host is not permitted by the acceptable-use policy.
422unknown_sitekeyThe sitekey/url pair did not resolve to a live gate. Usually a stale sitekey, or the wrong url for it.
429rate_limitedAbove the key or shared pass rate limit. Honor Retry-After before retrying.
502user_proxy_errorThe proxy you supplied refused or dropped the connection. Check its credentials, allowlist and egress region — or omit proxy to use our pool. — not billed
503target_unavailableToo many recent solves for this target failed, so attempts are paused briefly. — not billed
503maintenanceSolving is paused for platform maintenance. — not billed
504solve_timeoutThe wait or solve timed out. Queued work can still finish; retry with the same Idempotency-Key and body. — check final status

Full reference is in the API documentation, and every code is listed on the error page.

Where the cf_clearance cookie goes

A live WAF solve returns a JSON-encoded clearance object in token, containing cookies, set_cookies, headers, attributes and cf_rt:

CaseWhat to do with it
Decode the payloadUse JSON.parse(solve.token) in Node or json.loads(solve.token) in Python after checking status and meter. The SDKs return the string unchanged. Apply the returned cookies and headers to the target session.
Keep the request consistentCloudflare ties clearance to the visitor and device. Keep the same proxy and returned session headers when using the result.
Reuse itA valid cookie can cover later requests at its clearance level or below. Higher-level challenges and changes in session behavior can require another challenge before expiry.

The window is the site owner's setting, not ours. Thirty minutes is the common default; it can be configured far longer or shorter, so treat expiry as something to detect rather than assume.

When a Cloudflare challenge solver will not work

Four limits worth knowing before you build against this, because each one looks like a bug in your code when you hit it unprepared.

Clearance is tied to a visitor and device

Use the same proxy and returned session headers. Replaying clearance in a different session can fail, even if the cookie has not expired.

The lifetime is not ours to set

The site owner configures it. Watch for the challenge returning rather than counting on a duration.

It does not cover an embedded widget

A form on the far side of the interstitial can still carry its own Turnstile. That is a second, separate solve with gate=turnstile.

A cookie does not bypass every rule

A higher-level challenge can replace an existing clearance, and other security checks can still reject a request.

What it costs to clear a Cloudflare challenge

Credits are prepaid in packs and one credit is one successful solve. Bigger packs carry a lower effective rate; nothing is metered in arrears and nothing auto-renews.

PackPricePer 1,000 solves
30k credits$12$0.40
100k credits$25$0.25
250k credits$60$0.24
500k credits$100$0.20
1M credits$150$0.15
5M credits$600$0.12
10M credits$1,000$0.10
20M credits$1,500$0.075

Failed solves, timeouts and our internal retries are never billed. Credits do not expire. Full breakdown on the pricing page.

Cloudflare challenge solver questions

An interstitial Cloudflare serves instead of the site while it decides whether to let the request through. It is issued by the WAF rather than embedded by the site author, which is why it replaces the page rather than sitting inside a form. SolveGate treats it as gate=waf.

Turnstile is a widget the site owner embeds in their own markup and verifies server-side. A WAF challenge is served by Cloudflare's edge in front of the origin, so there is no form to attach a token to — clearing it is what lets the request reach the site at all.

A valid clearance cookie can cover later requests from the same visitor at its challenge level or below. A higher-level challenge or a change in session behavior can require another challenge before it expires.

A 1020 is a firewall rule denying the request outright — there is no challenge to solve, and no solver can help. If you are getting 1020 rather than an interstitial, the fix is at the rule level on a property you control, not at the solve level.

The same meter as Turnstile: prepaid credits from $0.40 per 1,000 solves down to $0.075 per 1,000 on the largest pack, with failed solves never billed.

The site owner sets it, not us. Thirty minutes is the common default and it can be configured far longer or shorter, so treat expiry as something to detect — watch for the challenge coming back — rather than a duration to hard-code. Cookie expiry is only one condition: clearance level and session checks still apply.

Check that you decoded the WAF token, applied the returned cookies and headers, and kept the same proxy and session. Cloudflare ties clearance to a visitor and device. A higher-level challenge or another security rule can also reject the next request.

Sometimes. Clearing the interstitial gets you the page; a form on that page can still carry its own embedded Turnstile widget, and that is a separate solve with gate=turnstile. A higher-level challenge or other security checks can also require additional verification.

Yes — send async: true and you get a pending solve back immediately, then poll GET /v1/solve/{id} until status leaves pending. Retrieval is free and never re-bills, so polling costs nothing but the request. It is the right shape when you are clearing many hosts at once and would rather not hold a connection open for each.

Sources

Other gates we clear

Working with Turnstile