Official CaptchaSonic library for Python.
The CaptchaSonic Python SDK is a modern, async-ready library designed for high-throughput automation. It features first-class type hints, dual-transport flexibility (gRPC + HTTP), and automatic retry logic.
Works in Python 3.10+ — scripts, notebooks, Django, FastAPI, Flask, and CLI tools.
pip install captchasonicFor HTTP transport (optional):
pip install "captchasonic[http]"from captchasonic import CaptchaSonic
solver = CaptchaSonic("YOUR_API_KEY")
result = solver.solve_recaptcha_v2(
images=[tile1, tile2, tile3],
question="traffic lights",
)
print(result["typed_solution"]["grid"]["objects"]) # [2, 4, 7]from captchasonic import CaptchaSonic
solver = CaptchaSonic("YOUR_API_KEY")
try:
result = solver.solve_geetest(
geetest_type="nine",
question="Select all bicycles",
images=tiles, # list[bytes | Path | str]
)
print("Solution:", result["typed_solution"])
except Exception as err:
print("Error:", err)The SDK ships a full async client with identical methods.
import asyncio
from captchasonic import AsyncCaptchaSonic
async def main():
async with AsyncCaptchaSonic("YOUR_API_KEY") as solver:
result = await solver.solve_geetest(
geetest_type="nine",
question="Select all bicycles",
images=tiles,
)
print("Solution:", result["typed_solution"])
asyncio.run(main())solver = CaptchaSonic(
"YOUR_API_KEY",
transport="grpc", # "grpc" (default) or "http"
url="api.captchasonic.com:443", # Override the API endpoint. Optional.
base_url=None, # Alias for url. Optional.
timeout=30.0, # Per-call timeout in seconds. Default: 30.
polling_interval=2.0, # Seconds between task polls. Default: 2.
polling_timeout=120.0, # Max seconds to wait for async task. Default: 120.
secure=True, # Use TLS for gRPC. Default: True.
)Transport guide:
| Transport | Environments | Protocol |
|---|---|---|
grpc (default) |
Server-side Python | gRPC binary over HTTP/2 — lowest latency |
http |
Universal | Plain REST/JSON via httpx |
grpcsends images as raw binary — zero base64 overhead.httpauto-encodes images to base64 before sending.
All methods accept keyword arguments with full type hints and docstrings.
solver.solve_popular_captcha(
images=list[ImageInput],
question=str, # e.g. "Select all traffic lights"
question_type=str, # "objectClassify" | "objectClick" | "objectDrag" | "grid"
examples=list[ImageInput], # optional
screenshot=bool, # optional, default False
website_url=str, # optional
website_key=str, # optional
)solver.solve_recaptcha_v2(
images=list[ImageInput],
question=str, # "traffic lights" or "/m/015qff"
question_type=str, # "split_33" | "33" | "44". Optional.
website_url=str, # optional
website_key=str, # optional
)solver.solve_geetest(
geetest_type=str, # "nine" | "click" | "slide" | "match" | "winlinze"
question=str, # required for "nine" and "click"
images=list[ImageInput], # required for "nine", "click", "slide"
examples=list[ImageInput], # optional
gtv=int, # Geetest version (e.g. 3). Optional.
website_url=str, # optional
)
# Type aliases also accepted:
# "nine" → "geetest_nine" | "9"
# "click" → "geetest_click" | "icon"
# "slide" → "geetest_slide"
# "match" → "geetest_match"
# "winlinze" → "geetest_winlinze"solver.solve_ocr(
images=list[ImageInput],
module=str, # "common" | "mtcaptcha" | "bls" | "morocco". Optional.
numeric=bool, # Expect only digits. Optional.
case_sensitive=bool, # Preserve letter case. Optional.
min_length=int, # Minimum text length. Optional.
max_length=int, # Maximum text length. Optional.
website_url=str, # optional
)
# Returns: result["typed_solution"]["text"]["texts"][0]solver.solve_tiktok(
type=str, # "click" | "whirl" | "slide" (or "tiktok_click" etc.)
question=str, # optional
images=list[ImageInput],
examples=list[ImageInput], # required for "whirl" and "slide"
website_url=str, # optional
)solver.solve_binance(
type=str, # "grid" | "slide" (or "binance_grid" etc.)
question=str, # required for "grid"
images=list[ImageInput],
examples=list[ImageInput], # optional
website_url=str, # optional
)solver.solve_aws_waf(
images=list[ImageInput],
question=str, # e.g. "grid:vehicles:cars"
website_url=str, # optional
website_key=str, # optional
)solver.solve_slide_image(images=[background, piece])
# Returns: result["typed_solution"]["slide"]["x"] — pixel offsetThese submit a task and poll until a token is returned (up to 120 s).
solver.solve_turnstile(website_url=..., website_key=..., proxy=...)
solver.solve_popular_captcha_token(website_url=..., website_key=..., proxy=..., metadata=...)
solver.solve_recaptcha_v2_token(website_url=..., website_key=..., proxy=...)
solver.solve_recaptcha_v3_token(website_url=..., website_key=..., proxy=...)
solver.solve_cloudflare(website_url=..., website_key=..., proxy=...) # proxy requiredbalance = solver.get_balance() # → float (USD)
solver.health_check() # → HealthCheckResponsefrom pathlib import Path
ImageInput = bytes | str | Path | BinaryIO
# File path
solver.solve_ocr(images=[Path("captcha.png")])
solver.solve_ocr(images=["./captcha.png"])
# Raw bytes
with open("captcha.png", "rb") as f:
solver.solve_ocr(images=[f.read()])
grpcsends images as raw binary — zero base64 overhead.httpauto-encodes images to base64 before sending.
from captchasonic import CaptchaSonic
from captchasonic.exceptions import SonicError
try:
result = solver.solve_geetest(geetest_type="nine", question="bicycles", images=tiles)
except SonicError as err:
print(err.error_id) # 1–6
print(type(err).__name__) # "InvalidApiKeyError" | "InsufficientBalanceError" | ...
print(err)error_id |
Exception | Meaning |
|---|---|---|
| 1 | InvalidApiKeyError |
API key not valid |
| 2 | InsufficientBalanceError |
Insufficient credits |
| 3 | DailyLimitExceededError |
Daily quota exceeded |
| 4 | MinuteLimitExceededError |
Rate limit hit |
| 5 | QuotaExceededError |
Plan quota exceeded |
| 6 | PlanExpiredError |
Subscription expired |
Transient gRPC errors are retried automatically with exponential backoff — up to 3 attempts.
# Sync — auto-closes gRPC channel / HTTP session
with CaptchaSonic("YOUR_API_KEY") as solver:
result = solver.solve_ocr(images=[Path("captcha.png")])
print(result["typed_solution"]["text"]["texts"][0])
# Async
async with AsyncCaptchaSonic("YOUR_API_KEY") as solver:
result = await solver.solve_ocr(images=[Path("captcha.png")])- Python ≥ 3.10
- gRPC transport —
grpcio,protobuf(included) - HTTP transport —
httpx(install withpip install captchasonic[http])
MIT — see LICENSE