Guide
CapSolver AI
Core SDK

Core SDK

The engine of the whole ecosystem. capsolver-core uses pure Python to detect CAPTCHAs on a page, read their parameters, solve them through the CapSolver AI service, and fill the token back in. The higher-level capsolver-agent and capsolver-mcp packages are both built on top of it.

Token mode only. This SDK solves by requesting a token from the CapSolver API (reCAPTCHA v2/v3, Cloudflare Turnstile). It does not click image grids or drag sliders on the page.

1. Overview

capsolver-core breaks “solving a CAPTCHA” into four clear stages, chained into a single pipeline:

  1. Detect (detect) — identify which CAPTCHA types are present on the page.
  2. Read parameters (get_captcha_info) — read the structured parameters of each CAPTCHA (type, site key, URL, and so on) straight from the live page.
  3. Solve (solve) — hand the parameters to CapSolver’s AI service and get back a usable token.
  4. Fill back (solve_on_page) — write the token back into the page DOM so the site treats verification as passed.

Around this pipeline, it adds several engineering conveniences:

  • Fully async API — built on async/await, so you can run a large number of solves concurrently.
  • Connection reuse and cleanup — maintains an internal HTTP connection pool and works as an async context manager.
  • Pluggable handler registry — each CAPTCHA type is handled by one handler, which you can customize or override.
  • Two levels of granularity — go pure API when the parameters are known; use Playwright Browser mode when all you have is the page.

When should you use core directly? When you control the code yourself and don’t need to expose solving to an LLM.

2. Installation

capsolver-core is open source on GitHub and not yet published to PyPI, so install it via git:

pip install git+https://github.com/capsolver-ai/capsolver-core.git
 
# With Playwright support (for detect / solve_on_page)
pip install "capsolver-core[playwright] @ git+https://github.com/capsolver-ai/capsolver-core.git"
playwright install chromium

Set your key:

export CAPSOLVER_API_KEY="your-capsolver-api-key"

Note: The SDK works without the [playwright] extra — in that case only Token mode (solve) is available, and the browser-dependent methods detect / get_captcha_info / solve_on_page are unavailable because Playwright is missing.

3. The API & the Two Modes

3.1 Create a Client

create_capsolver(**options) (or Capsolver(**options)) returns a client.

OptionDefaultDescription
api_keyCapSolver client key (required for solving)
servicehttps://api.capsolver.comAPI base URL
default_timeout120Total polling budget, in seconds
polling_interval5Interval between result polls, in seconds
request_timeout_ms30000Timeout for a single HTTP request
app_idDeveloper / affiliate ID
handlersAll built-inOverride the registered CAPTCHA handlers
sourceTraffic-source identifier
versionClient version tag
on_errorCallback for non-fatal errors

Capsolver holds an internal HTTP connection pool, so it’s best used as an async context manager to ensure connections are released:

async with create_capsolver(api_key="YOUR_API_KEY") as cap:
    solution = await cap.solve(info)
# or call await cap.aclose() explicitly when you're done

3.2 Methods at a Glance

MethodParametersReturnsDescription
solve(info, wait_options?)CaptchaInfo, WaitOptions?SolutionSolve from parameters
detect(page)Playwright pagelist[CaptchaType]Which CAPTCHAs are on the page
get_captcha_info(page)Playwright pagelist[CaptchaInfo]Structured parameters for each widget
solve_on_page(page, options?)page, SolveOnPageOptions?list[SolveOnPageResult]Detect → solve → fill back
get_balance()BalanceRespAccount balance
register(handler)CaptchaHandlerAdd a handler to the registry
get_supported_captchas()list[str]List the supported types
get_handler(key)str / CaptchaTypeCaptchaHandler | NoneLook up a handler by key

3.3 Solve Input: CaptchaInfo

The core input to solve() is a CaptchaInfo. type, website_url, and website_key are required (an empty website_url or website_key raises ValueError); the rest are optional depending on the CAPTCHA type:

ParameterTypeRequiredApplies toDescription
typeCaptchaTypeYesAllRECAPTCHA_V2 / RECAPTCHA_V3 / CLOUDFLARE
website_urlstrYesAllFull URL of the page hosting the CAPTCHA
website_keystrYesAllSite public key (reCAPTCHA’s data-sitekey / Turnstile’s sitekey)
versionstrNoreCAPTCHA"v2" or "v3"; usually auto-detected
page_actionstrNoreCAPTCHA v3The v3 action name (e.g. "login")
min_scorefloatNoreCAPTCHA v3Desired minimum score (0.0–1.0)
invisibleboolNoreCAPTCHA v2Whether this is invisible v2
enterpriseboolNoreCAPTCHAWhether to use the Enterprise variant
sstrNoreCAPTCHA EnterpriseThe Enterprise s token
cdatastrNoCloudflareTurnstile’s cdata custom parameter
proxystrNoAllProxy, as user:pass@host:port or host:port
user_agentstrNoAllCustom User-Agent
container_idstrNoBrowser fill-backDOM id used to locate the widget container during fill-back
callbackstrNoBrowser fill-backName of the callback function to trigger after solving
binded_button_idstrNoBrowser fill-backDOM id of the associated submit button
extradictNoAllPass-through for fields not yet modeled

The options for solve_on_page() are controlled by SolveOnPageOptions:

OptionTypeDefaultDescription
autofillboolTrueWhether to automatically fill the token back into the page DOM after solving
throw_on_errorboolFalseOn a single CAPTCHA failure, whether to raise an exception or record it in the error field
timeoutfloatClient defaultTotal polling budget for this call, in seconds
polling_intervalfloatClient defaultPolling interval for this call, in seconds

The wait_options for solve() (WaitOptions) has only two optional fields, timeout and polling_interval, used to override the client’s global defaults for a single solve.

3.4 Return Types

TypeFieldDescription
SolutiontokenThe solved token — the credential you submit to the target site
captcha_typeThe CAPTCHA type that was solved
expire_timeToken expiry in seconds (only present when the service returns it)
user_agentThe UA used to solve (only present when the service returns it)
rawThe raw TokenSolution (contains g_recaptcha_response, etc.)
SolveOnPageResultinfoThe CaptchaInfo for that CAPTCHA
solutionThe Solution; None on failure
filledWhether the token was filled back into the page
errorReason for failure; None on success
BalanceRespbalanceAccount balance (float)
packagesList of plans / subscription packages

detect() returns list[CaptchaType], and get_captcha_info() returns list[CaptchaInfo].

3.5 How Each Mode Uses These APIs

The only difference between the two modes is where the parameters come from — which is why they call different APIs:

Token mode (you already know the site key) — uses only solve(). You construct the CaptchaInfo yourself and get a token back:

info = CaptchaInfo(type=CaptchaType.RECAPTCHA_V2, website_url=..., website_key=...)
solution = await cap.solve(info)

Browser mode (driving the page with Playwright) — uses detect() / get_captcha_info() / solve_on_page(). The all-in-one solve_on_page() covers detection, solving, and fill-back; or you can run the steps separately to control each stage yourself:

results = await cap.solve_on_page(page)              # all in one call
# or step by step:
types = await cap.detect(page)
infos = await cap.get_captcha_info(page)
solution = await cap.solve(infos[0])

4. Calling Each API: Requests & Responses

This section walks through each method individually — the real call, the parameters to pass, a sample response, and an explanation of the response fields.

4.1 solve — Solve (Token mode)

Example call and response:

import asyncio
from capsolver_core import create_capsolver, CaptchaType, CaptchaInfo
 
async def main():
    cap = create_capsolver(api_key="YOUR_API_KEY")
 
    info = CaptchaInfo(
        type=CaptchaType.RECAPTCHA_V2,        # required: CAPTCHA type
        website_url="https://example.com",    # required: page URL
        website_key="6Lc...",                 # required: site public key (data-sitekey)
        # v3 also takes page_action / min_score; Enterprise takes enterprise/s; Cloudflare takes cdata
    )
    solution = await cap.solve(info)
    print(solution.token)
 
asyncio.run(main())

Sample response (Solution):

Solution(
  token="03AFcWeA6f...",                  # the credential to submit to the target site
  captcha_type=CaptchaType.RECAPTCHA_V2,
  expire_time=120,
  user_agent="Mozilla/5.0 ...",
  raw=TokenSolution(...),
)

Response fields:

  • token — the solved token; submit it as g-recaptcha-response for reCAPTCHA or cf-turnstile-response for Turnstile.
  • captcha_type — the CAPTCHA type that was solved.
  • expire_time — token expiry in seconds; present only when the service returns it, otherwise None.
  • user_agent — the UA used to solve; present only when the service returns it, otherwise None.
  • raw — the raw TokenSolution, containing g_recaptcha_response / token / user_agent / expire_time.

4.2 solve_on_page — Whole-page detect + solve + fill-back (Browser mode)

Call and parameters: the input is a Playwright page, with an optional SolveOnPageOptions.

import asyncio
from capsolver_core import create_capsolver
from playwright.async_api import async_playwright
 
async def main():
    cap = create_capsolver(api_key="YOUR_API_KEY")
 
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.goto("https://example.com/login")
 
        results = await cap.solve_on_page(page)   # or pass options=SolveOnPageOptions(...)
        for r in results:
            print(r.info.type, r.solution.token if r.solution else None, r.filled, r.error)
 
asyncio.run(main())

Sample response (list[SolveOnPageResult]):

[
  SolveOnPageResult(
      info=CaptchaInfo(type=CaptchaType.RECAPTCHA_V2, website_url=..., website_key=...),
      solution=Solution(token="03AF...", captcha_type=CaptchaType.RECAPTCHA_V2),
      filled=True,
      error=None,
  ),
]

Response fields (per item):

  • info — the CaptchaInfo for that CAPTCHA (type and parameters).
  • solution — the Solution; None on failure.
  • filled — whether the token was successfully filled back into the page.
  • error — failure reason string; None on success.

4.3 detect — Detect which CAPTCHAs are on the page

Call and parameters: the input is a Playwright page.

types = await cap.detect(page)

Sample response / fields (list[CaptchaType]):

[<CaptchaType.RECAPTCHA_V2: 'reCaptchaV2'>]

Returns a list of the CAPTCHA-type enums detected on the page; an empty list means none were found.

4.4 get_captcha_info — Read structured parameters

Call and parameters: the input is a Playwright page.

infos = await cap.get_captcha_info(page)
for info in infos:
    print(info.type, info.website_url, info.website_key)
solution = await cap.solve(infos[0])     # once read, can be solved directly

Sample response / fields (list[CaptchaInfo]):

# [CaptchaInfo(type=CaptchaType.RECAPTCHA_V2,
#              website_url="https://example.com",
#              website_key="6Lc...")]

4.5 get_balance — Check balance

Call and parameters: no input.

balance = await cap.get_balance()
print(balance.balance, balance.packages)

Sample response / fields (BalanceResp):

BalanceResp(balance=12.34, packages=[])
  • balance — account balance (float).
  • packages — list of plans / subscription packages; an empty list if there are none.

4.6 get_supported_captchas / get_handler — Registry access

Call and response:

cap.get_supported_captchas()      # → ['reCaptchaV2', 'reCaptchaV3', 'cloudflare']
  • get_supported_captchas() — returns a list of the currently supported type strings.