Agent
Bring CapSolver’s solving capability into any LLM / agent framework. capsolver-agent is a thin layer over the capsolver-core engine: it wraps the core’s solve / detect / solve_on_page methods as tools an LLM can call, making the “model decides, core executes” boundary fall into place naturally.
Division of labor: the model handles navigation and decision-making,
capsolver-corehandles solving, andcapsolver-agentis the tool-adapter layer in between — the model calls “solve” the same way it calls “click” or “type,” without having to click the CAPTCHA itself.
1. How capsolver-agent Relates to capsolver-core
You almost never write core call code directly. When the LLM decides to call a tool, the agent layer’s executor calls the corresponding core method for you and returns a structured result to the model:
LLM (decides)
│ emits a tool call, e.g. solve_captcha(...)
▼
capsolver-agent (schema + executor) ← tool-adapter layer
│ executor.execute(...) internally relays to ↓
▼
capsolver-core (solve / detect / solve_on_page)
│
▼
CapSolver APIEach agent tool maps directly to one core method — which is where the core does the real work in every scenario:
| Agent tool | Underlying capsolver-core method | Browser? |
|---|---|---|
solve_captcha | cap.solve(info) | No |
detect_captchas | cap.detect(page) | Yes |
solve_on_page | cap.solve_on_page(page) | Yes |
get_balance | cap.get_balance() | No |
get_supported_captchas | cap.get_supported_captchas() | No |
2. Installation
capsolver-agent is built on top of capsolver-core (the core does the solving) and depends on it at runtime. Both are open source on GitHub and not yet published to PyPI, and capsolver-agent depends on capsolver-core by name. Install core first, then agent:
# 1) Install the core engine first (agent depends on it)
pip install git+https://github.com/capsolver-ai/capsolver-core.git
# 2) Then install agent itself
pip install git+https://github.com/capsolver-ai/capsolver-agent.gitAdd extras as needed:
# With LangChain support
pip install "capsolver-agent[langchain] @ git+https://github.com/capsolver-ai/capsolver-agent.git"
# With Playwright (detect / solve_on_page)
pip install "capsolver-agent[browser] @ git+https://github.com/capsolver-ai/capsolver-agent.git"export CAPSOLVER_API_KEY="your-capsolver-api-key"3. Usage: Wiring Solving into the Conversation Loop
Integration lands inside the model’s “conversation–tool” loop. One full round runs like this:
1. Hand the tools to the model ───────────────────┐
2. The model answers and decides: do I need a tool here?
├─ No → return the final answer, done │
└─ Yes → return a tool_call │
3. You execute the call → relay to core → get a result
4. Feed the result back to the model ─────────────┘ back to step 2, next roundIn practice, the model decides whether and which tool to use; your job is to wire core into this loop, in three steps: connect core → hand the tools to the model → execute the calls the model returns inside the loop, stringing them into a working loop.
3.1 Connect core: create an executor
The thing that actually solves is always capsolver-core’s Capsolver engine. The agent layer only adds a ToolExecutor around it: internally it holds a Capsolver, dispatches the model’s tool calls to the engine’s corresponding methods, and wraps the return into a structured result. Below we first show how this wrapper is assembled, then the one-line shorthand.
How the executor loads core. Spelled out, it’s two lines, with core created on the first:
from capsolver_core import Capsolver # capsolver-core engine
from capsolver_agent.schema import ToolExecutor
cap = Capsolver(api_key="YOUR_CAPSOLVER_KEY") # the same Capsolver from the "Core SDK" page
executor = ToolExecutor(cap) # wrap a "tool call → core method" dispatcher around itThe dispatch is a fixed mapping; every tool call ultimately lands on a core method:
executor.execute("solve_captcha", {...}) # → cap.solve(CaptchaInfo(...))
executor.execute("detect_captchas", {...}) # → cap.detect(page)
executor.execute("get_balance", {}) # → cap.get_balance()On each call, the executor assembles the tool arguments into the form core expects, calls core, and wraps the result (or error) into a dict you can feed straight back to the model — success is {"success": True, "solution": {...}}, failure is {"success": False, "error": "..."}. So the methods and parameters you learned on the Core SDK page apply here unchanged.
Usage. The two lines above have a ready-made wrapper; in everyday use, just call it:
from capsolver_agent.schema import create_executor
executor = create_executor(api_key="YOUR_CAPSOLVER_KEY") # == Capsolver(...) + ToolExecutor(...)When you want to customize core’s behavior, any extra keyword arguments passed to create_executor() are forwarded as-is to Capsolver(...) — for example, create_executor(api_key=..., default_timeout=180).
3.2 Hand the tools to the model
get_all_tools() gives you all the tool definitions — the outward-facing description of core’s capabilities. Export them in your target framework’s format and pass them to the model as its function-calling interface:
from capsolver_agent.schema import get_all_tools
tools = [t.to_openai_function() for t in get_all_tools()]
# to_openai_function() → {"type": "function", "function": {...}}, the format OpenAI's tools= expects
# you can also use t.to_json_schema() → an MCP-style tool description (name + inputSchema)3.3 Execute the call the model returns, relaying to core
When the model returns a tool_call at some step, hand it to the executor from 3.1 — execute(tool_name, args) dispatches the call to the corresponding core method (solve / detect / solve_on_page …), returns a structured result, and you feed that back to the model:
result = await executor.execute("solve_captcha", {
"captcha_type": "reCaptchaV2",
"website_url": "https://example.com",
"website_key": "6Le-wvkSAAAAAPBMRT...",
})
# result → {"success": True, "solution": {"token": "03AF...", ...}}3.4 String it into a complete loop
Embed the three steps above into the model’s conversation loop, and you have a minimal agent that solves CAPTCHAs on its own (using OpenAI function calling as the example):
import asyncio, json
from openai import OpenAI
from capsolver_agent.schema import get_all_tools, create_executor
client = OpenAI() # your LLM client
executor = create_executor(api_key="YOUR_CAPSOLVER_KEY") # 3.1 connect core
tools = [t.to_openai_function() for t in get_all_tools()] # 3.2 hand tools to the model
async def run(prompt: str) -> str:
messages = [{"role": "user", "content": prompt}]
while True:
resp = client.chat.completions.create(model="gpt-4o", messages=messages, tools=tools)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls: # model no longer calls a tool
return msg.content # → final answer, exit the loop
for call in msg.tool_calls: # model wants to call a tool
result = await executor.execute( # 3.3 execute → relay to core
call.function.name,
json.loads(call.function.arguments),
)
messages.append({ # feed the result back, next round
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result),
})
asyncio.run(run("Solve the reCAPTCHA v2 on https://example.com for me; the sitekey is 6Lc..."))When you only want to run a tool once rather than build the whole loop, call execute_tool(name, args, api_key=...) in a single shot.
4. Per Framework: the Same Loop, a Different Shell
The two steps above are the universal skeleton. When you connect to a specific framework, the only differences are who drives the “call a tool → feed the result back” loop, and which of core’s capabilities you use — known site parameters go through Token mode (solve()), while autonomously driving the page goes through Browser mode (detect() / solve_on_page()).
| Scenario / framework | Core capability used | How to integrate | Example file |
|---|---|---|---|
| OpenAI function calling | solve() (Token mode) | You drive the loop: feed the schema to the model + executor runs it | openai_function_calling.py |
| OpenAI Agents SDK | solve(), etc. | The runtime drives the loop: @function_tool wraps execute_tool | openai_agents.py |
| LangChain ReAct | solve(), etc. | Use get_langchain_tools() for ready-made BaseTools | langchain_agent.py |
| Browser Use | detect() / solve_on_page() | @tools.action registers solving as an action | browser_use_agent.py |
| Playwright (no LLM) | detect() / solve_on_page() | Use capsolver-core directly, bypassing the agent layer | playwright_sdk.py |
Of these, Browser Use is closest to real-world automation: the agent browses on its own, and when it hits a CAPTCHA mid-task, it calls solving as an action — detecting, solving, and filling back within the same browser session, then continuing the original flow once it has the result, without breaking stride:
Agent browses the page → hits a CAPTCHA → calls the solve action (core: solve_on_page) → gets a token → continues the task5. Running the Examples
Every scenario in the table above ships with a runnable example, all under examples/ in the agent repository. Clone it, install the dependencies, and run.
git clone https://github.com/capsolver-ai/capsolver-agent.git
cd capsolver-agent
uv sync
export CAPSOLVER_API_KEY=CAP-XXXXXX
export OPENAI_API_KEY=sk-XXXXXX # required by the LLM-based examplesEach example’s extra dependencies (capsolver-agent / capsolver-core install from GitHub; the rest are regular PyPI packages):
# OpenAI Function Calling
pip install openai
# OpenAI Agents SDK
pip install openai-agents
# LangChain
pip install "capsolver-agent[langchain] @ git+https://github.com/capsolver-ai/capsolver-agent.git" langchain-openai langgraph
# Browser Use
pip install browser-use langchain-openai playwright && playwright install chromium
# Playwright (no LLM)
pip install git+https://github.com/capsolver-ai/capsolver-core.git playwright && playwright install chromium