CAPSOLVER
Blog
How to Solve Cloudflare Turnstile in LlamaIndex Agents

How to Solve Cloudflare Turnstile in LlamaIndex Agents

Logo of CapSolver

Aloísio Vítor

How to use CapSolver

27-Aug-2026

TL;DR

  • Wrap a narrow CapSolver Turnstile function with LlamaIndex FunctionTool.from_defaults().
  • Use the documented AntiTurnstileTaskProxyLess task with the exact page URL and site key.
  • Send action and cdata only when the authorized page exposes those optional values.
  • Return the solution token to deterministic browser code instead of storing it in long-lived agent memory.
  • Add approved-host validation, one bounded retry, trace redaction, and a human-review branch before production.

Introduction

The safest way to solve Cloudflare Turnstile in LlamaIndex agents is to expose CapSolver as a typed function tool while keeping browser state, secrets, and authorization checks outside the model. LlamaIndex can decide that a supported challenge blocks the next approved step, but deterministic Python should validate the target, build the documented AntiTurnstileTaskProxyLess, and return a short-lived solution token to the browser controller. This follows the CapSolver AI Agent architecture: the model decides, a tool adapter defines the action, and the core solving layer executes it. This guide shows the exact Turnstile fields, a LlamaIndex FunctionTool implementation, a FunctionAgent workflow, secure token handoff, bounded retries, and responsible-use controls for QA, RPA, and permitted browser automation.

Why LlamaIndex FunctionTool Is a Good Fit

LlamaIndex treats tools as agent-facing APIs. Its official tools documentation explains that FunctionTool can wrap synchronous or asynchronous Python functions and infer a schema from the function signature. The tool name, description, annotations, and docstring influence when the model calls it.

That boundary is useful for challenge recovery because the model should never generate arbitrary solving code or receive a CapSolver API key. A narrow function can accept only an approved page URL, a Turnstile site key, and optional widget metadata.

The CapSolver AI blog covers agent integrations, while the CapSolver AI and automation FAQ explains how challenge recovery complements an existing agent stack.

Understand the Official Turnstile Task

CapSolver's Cloudflare Turnstile documentation specifies AntiTurnstileTaskProxyLess. The task requires websiteURL and websiteKey. Optional metadata can include the widget's action and cdata values.

Field Required Source Purpose
type Yes Fixed AntiTurnstileTaskProxyLess
websiteURL Yes Approved current page Associates the solution with the page
websiteKey Yes Turnstile widget Identifies the widget configuration
metadata.action No data-action Preserves a widget action value
metadata.cdata No data-cdata Preserves customer data used by the widget

CapSolver automatically supports managed, non-interactive, and invisible Turnstile presentations, so the task does not need a subtype. Cloudflare's Turnstile documentation describes the widget and the server-side validation process used by the site owner.

Install LlamaIndex and CapSolver

bash Copy
pip install llama-index llama-index-llms-openai capsolver

For the broader CapSolver agent architecture provided in the user's documentation, install the core and agent packages as well:

bash Copy
pip install git+https://github.com/capsolver-ai/capsolver-core.git
pip install git+https://github.com/capsolver-ai/capsolver-agent.git

Configure secrets outside the prompt:

bash Copy
export CAPSOLVER_API_KEY="CAP-xxxxxxxxxxxxxxxx"
export OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxx"

The direct SDK example below uses the exact Turnstile task fields. LlamaIndex supplies the framework shell; CapSolver performs the task.

Create a Typed Turnstile Function

Validate the URL before sending it to CapSolver. The model should not be able to select an arbitrary hostname.

python Copy
import os
from typing import Annotated
from urllib.parse import urlparse

import capsolver

capsolver.api_key = os.environ["CAPSOLVER_API_KEY"]

ALLOWED_HOSTS = {
    "staging.example.com",
    "qa.example.com",
}


def solve_turnstile(
    website_url: Annotated[str, "Approved HTTPS page containing Turnstile"],
    website_key: Annotated[str, "Exact Turnstile site key from the page"],
    action: Annotated[str, "Optional data-action value"] = "",
    cdata: Annotated[str, "Optional data-cdata value"] = "",
) -> dict:
    """Solve Cloudflare Turnstile for an approved page and return a token."""
    parsed = urlparse(website_url)
    if parsed.scheme != "https" or parsed.hostname not in ALLOWED_HOSTS:
        return {
            "success": False,
            "error": "Target is outside the approved hostname allowlist",
        }

    if not website_key.startswith("0x4"):
        return {
            "success": False,
            "error": "Unexpected Turnstile site-key format",
        }

    task = {
        "type": "AntiTurnstileTaskProxyLess",
        "websiteURL": website_url,
        "websiteKey": website_key,
    }

    metadata = {}
    if action:
        metadata["action"] = action
    if cdata:
        metadata["cdata"] = cdata
    if metadata:
        task["metadata"] = metadata

    try:
        solution = capsolver.solve(task)
        token = solution.get("token")
        if not token:
            return {"success": False, "error": "No token returned"}
        return {
            "success": True,
            "token": token,
            "solution_type": solution.get("type", "turnstile"),
        }
    except Exception as exc:
        return {"success": False, "error": str(exc)}

The format check is a useful early warning, but it does not replace exact parameter extraction from the authorized page. Use the CapSolver browser extension guide when you need to inspect a widget's configuration during development.

Wrap the Function with LlamaIndex

FunctionTool.from_defaults() converts the function signature and docstring into an agent tool schema.

python Copy
from llama_index.core.tools import FunctionTool

turnstile_tool = FunctionTool.from_defaults(
    fn=solve_turnstile,
    name="solve_turnstile",
    description=(
        "Solve Cloudflare Turnstile only for an approved HTTPS page. "
        "Use the exact page URL, site key, and optional action/cdata "
        "provided by the trusted browser controller."
    ),
)

Keep the name short and the description operational. Do not describe the tool as a general access mechanism. The model should understand that it is a recovery action inside an already approved workflow.

Add the Tool to a LlamaIndex FunctionAgent

LlamaIndex's FunctionAgent uses an LLM's tool-calling capability to choose and execute tools.

python Copy
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.llms.openai import OpenAI

llm = OpenAI(model="gpt-4o-mini", temperature=0)

agent = FunctionAgent(
    tools=[turnstile_tool],
    llm=llm,
    system_prompt=(
        "You operate only approved browser workflows. "
        "Call solve_turnstile only when the trusted application supplies "
        "an exact page URL and site key. Never invent targets, keys, "
        "actions, or cdata. Call the tool once. If it fails, stop and "
        "request operator review."
    ),
)

Start the run with parameters produced by deterministic browser code:

python Copy
import asyncio

async def main():
    response = await agent.run(
        "The approved staging workflow found Turnstile at "
        "https://staging.example.com/account-check with site key "
        "0x4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA and action "
        "account_check. Call the registered tool once and return "
        "the structured result."
    )
    print(response)

asyncio.run(main())

In production, avoid constructing this message directly from untrusted user text. The browser controller should extract, validate, and serialize the values.

Keep Token Consumption Outside the Model

A Turnstile token is short-lived and tied to the site workflow. Pass it directly from the trusted tool result to deterministic browser code when possible.

python Copy
async def apply_turnstile_token(page, token: str) -> None:
    await page.evaluate(
        """
        (token) => {
          const field = document.querySelector(
            'input[name="cf-turnstile-response"]'
          );
          if (!field) {
            throw new Error('Turnstile response field not found');
          }
          field.value = token;
          field.dispatchEvent(new Event('input', { bubbles: true }));
          field.dispatchEvent(new Event('change', { bubbles: true }));
        }
        """,
        token,
    )

Some applications use callback-based rendering or server-managed submission. Test against your own staging application and follow its supported integration. Cloudflare's Siteverify documentation explains that the site owner validates the token server-side.

The CapSolver Turnstile guide provides implementation context, and the CapSolver troubleshooting FAQ helps diagnose rejected solutions.

Add One Bounded Retry

Do not let an agent loop indefinitely. Classify validation failures as final, and permit at most one retry for a transient timeout.

python Copy
import asyncio

async def solve_with_policy(params: dict) -> dict:
    last_error = "unknown error"

    for attempt in range(1, 3):
        result = solve_turnstile(**params)
        if result.get("success"):
            return {**result, "attempt": attempt}

        last_error = result.get("error", last_error)
        normalized = last_error.lower()
        if "allowlist" in normalized or "site-key" in normalized:
            break
        if attempt == 1:
            await asyncio.sleep(2)

    return {
        "success": False,
        "error": last_error,
        "requires_operator_review": True,
    }

Log the hostname, task type, duration, attempt count, and normalized outcome. Never log the full token, API key, cookies, or form contents.

Token Mode vs Browser Mode

Mode Best for Input Output
Token mode Known Turnstile URL and site key URL, key, optional metadata Solution token
Browser mode Dynamic widgets in an existing Playwright session Live page object Page recovery result
Human review Repeated failure or unsupported state Redacted error and screenshot reference Operator decision

The user-provided CapSolver Agent documentation maps solve_captcha to core token solving and solve_on_page to browser recovery. If the page is dynamic, install the browser extra and keep the original browser session intact:

bash Copy
pip install "capsolver-agent[browser] @ git+https://github.com/capsolver-ai/capsolver-agent.git"

Use the CapSolver automation tutorials for related browser workflows and the CapSolver products page for supported solution categories.

Bonus Code: Use code WEBS at CapSolver Dashboard to get an extra 5% bonus on every recharge.

Production Controls

A production LlamaIndex Turnstile integration should use an approved-host registry, secret isolation, short-lived token handoff, one bounded retry, trace redaction, operator review, and a strict separation between read-only automation and high-impact actions.

Control Recommended implementation
Target permission Tenant-specific HTTPS allowlist
Parameter source Trusted browser controller
Secret storage Executor environment only
Retry policy One retry for transient errors
Token handling Direct handoff to browser; no long-term storage
Tracing Redact tokens and cookies
Final actions Require confirmation for submissions or changes

The CapSolver CAPTCHA-solving FAQ explains the task lifecycle, and the CapSolver web-scraping FAQ covers operational considerations.

Responsible Use

Use this integration only on applications you own, test, or have explicit permission to automate. Challenge solving does not grant authorization to access private data, create accounts, submit transactions, or ignore site terms. Apply rate limits, maintain an audit trail, and require confirmation before any action that changes data or affects users.

Conclusion

To solve Cloudflare Turnstile in LlamaIndex reliably, make CapSolver a narrow FunctionTool and keep authorization, secrets, retries, and token consumption in deterministic code. The LlamaIndex agent decides when recovery is needed, the tool creates the documented AntiTurnstileTaskProxyLess, and the browser resumes the same approved workflow with the returned token.

Start with CapSolver, validate the integration against a staging page you control, and add allowlists and trace redaction before production.

FAQ

Which LlamaIndex tool class should I use?

Use FunctionTool.from_defaults() to wrap a typed sync or async Python function. For a tool-calling model, pass the resulting tool to FunctionAgent.

Does the Turnstile task require a proxy?

The documented AntiTurnstileTaskProxyLess uses CapSolver's proxyless task path, so you do not provide a proxy in the task.

Which fields are required?

websiteURL and websiteKey are required. Include metadata.action and metadata.cdata only when the authorized widget exposes them.

Should the token be stored in LlamaIndex memory?

No. Prefer a direct handoff to trusted browser code and return only a redacted success or failure state to the agent.

What should happen after repeated failure?

Verify the URL, site key, optional metadata, and page state. After one bounded retry, stop and route the workflow to operator review.

Compliance Disclaimer: The information provided on this blog is for informational purposes only. CapSolver is committed to compliance with all applicable laws and regulations. The use of the CapSolver network for illegal, fraudulent, or abusive activities is strictly prohibited and will be investigated. Our captcha-solving solutions enhance user experience while ensuring 100% compliance in helping solve captcha difficulties during public data crawling. We encourage responsible use of our services. For more information, please visit our Terms of Service and Privacy Policy.

More