python3-capsolver is a Python 3.8+ client library for the Capsolver captcha-solving API (Observed: pyproject.toml lines 38–43, src/python3_capsolver/core/const.py line 18). It provides a unified interface for submitting captcha tasks to Capsolver's cloud service and polling for results, covering ReCaptcha, Cloudflare Turnstile, GeeTest, DataDome, AWS WAF, MtCaptcha, FriendlyCaptcha, Yandex SmartCaptcha, image-to-text OCR, and AI vision tasks (Observed: src/python3_capsolver/core/enum.py CaptchaTypeEnm, service files in src/python3_capsolver/).
The library is a single-package SDK distributed via PyPI as python3-capsolver. It exposes a dual sync/async API — synchronous calls use requests, asynchronous calls use aiohttp — so consumers can integrate it into either threading or asyncio applications without switching libraries (Observed: pyproject.toml lines 86–91, core/sio_captcha_instrument.py imports requests, core/aio_captcha_instrument.py imports aiohttp).
Architecturally the codebase is a layered library: thin per-captcha-type service classes at the top, a shared base class that merges payloads and delegates to HTTP instruments, and a support layer of serializers, enums, and constants at the bottom. There is no server, no CLI, and no database — the library is a pure API client.
Evidence anchors: pyproject.toml, src/python3_capsolver/core/base.py, src/python3_capsolver/core/enum.py, src/python3_capsolver/core/const.py, src/python3_capsolver/recaptcha.py, src/python3_capsolver/core/serializer.py.
Four layers with strict top-to-bottom dependency direction:
┌─────────────────────────────────────────────┐
│ Service layer │
│ (recaptcha.py, cloudflare.py, control.py, │
│ gee_test.py, aws_waf.py, ...) │
│ Thin wrappers: __init__ only, zero HTTP │
└──────────────────┬──────────────────────────┘
│ inherits CaptchaParams
▼
┌─────────────────────────────────────────────┐
│ Base layer │
│ (core/base.py: CaptchaParams) │
│ Merges task payloads, delegates to │
│ sync/async instruments │
└──────────────────┬──────────────────────────┘
│ creates instrument instances
▼
┌─────────────────────────────────────────────┐
│ Instrument layer │
│ (core/sio_captcha_instrument.py — sync, │
│ core/aio_captcha_instrument.py — async, │
│ core/captcha_instrument.py — base + files) │
│ All HTTP, retries, and result-polling │
└──────────────────┬──────────────────────────┘
│ uses
▼
┌─────────────────────────────────────────────┐
│ Support layer │
│ (core/serializer.py — msgspec.Struct, │
│ core/enum.py — CaptchaTypeEnm etc., │
│ core/const.py — URLs, retry config, │
│ core/context_instr.py — context managers, │
│ core/utils.py — attempt generator) │
└─────────────────────────────────────────────┘
Dependency direction: Service → Base → Instrument → Support. Never upward (Observed: import graph in all source files follows this direction; no lower layer imports from an upper layer).
What each layer does NOT depend on:
- Service layer never imports
requests,aiohttp, or any HTTP library directly (Observed: all service files import only fromcore.baseandcore.enum). - Base layer never performs HTTP calls itself — it delegates to instrument instances (
Observed:core/base.pyhas no HTTP imports). - Support layer never depends on service, base, or instrument layers (
Observed:serializer.py,enum.py,const.py,utils.py,context_instr.pyimport only stdlib andmsgspec/tenacity).
Key boundary: control.py is architecturally distinct from the other service files. It bypasses the create-then-poll abstraction and calls instrument methods directly (get_balance, create_task, get_task_result) (Observed: control.py imports AIOCaptchaInstrument and SIOCaptchaInstrument directly, unlike other services which rely solely on CaptchaParams.captcha_handler() / aio_captcha_handler()).
.
├── src/python3_capsolver/ # Library source (setuptools package root)
│ ├── core/ # Shared infrastructure
│ │ ├── base.py # CaptchaParams — base class all services inherit
│ │ ├── captcha_instrument.py # CaptchaInstrumentBase (abstract) + FileInstrument
│ │ ├── sio_captcha_instrument.py # Sync instrument: requests-based HTTP + polling
│ │ ├── aio_captcha_instrument.py # Async instrument: aiohttp-based HTTP + polling
│ │ ├── serializer.py # msgspec.Struct request/response models
│ │ ├── enum.py # CaptchaTypeEnm, ResponseStatusEnm, EndpointPostfixEnm
│ │ ├── const.py # REQUEST_URL, RETRIES, ASYNC_RETRIES, APP_ID
│ │ ├── context_instr.py # SIOContextManager, AIOContextManager mixins
│ │ └── utils.py # attempts_generator (retry loop control)
│ ├── control.py # Raw API access (balance, create_task, get_task_result)
│ ├── recaptcha.py # ReCaptcha V2/V3/Enterprise solver
│ ├── cloudflare.py # Cloudflare Turnstile/Challenge solver
│ ├── gee_test.py # GeeTest V3/V4 solver
│ ├── datadome_slider.py # DataDome slider solver
│ ├── mt_captcha.py # MtCaptcha solver
│ ├── aws_waf.py # AWS WAF bypass solver
│ ├── friendly_captcha.py # FriendlyCaptcha solver
│ ├── yandex.py # Yandex SmartCaptcha solver
│ ├── image_to_text.py # OCR image-to-text solver
│ ├── vision_engine.py # AI vision engine solver
│ ├── __init__.py # Exports __version__ only — no re-exports
│ └── __version__.py # Version string
│
├── tests/ # Pytest integration test suite (mirrors src/ layout)
│ ├── conftest.py # BaseTest class, rate-limiting fixtures
│ ├── files/ # Test assets (captcha images)
│ └── test_*.py # One test file per service + test_core + test_instrument
│
├── docs/ # Sphinx documentation source
├── pyproject.toml # Build config, dependencies, tool settings
├── Makefile # make tests, refactor, lint, build, doc
└── .coveragerc # Coverage: measures python3_capsolver/ only
Where is X?
- A new captcha type → create a file in
src/python3_capsolver/, inheritCaptchaParams, register the type incore/enum.pyCaptchaTypeEnm. - HTTP retry configuration →
core/const.py(RETRIES,ASYNC_RETRIES). - API payload schemas →
core/serializer.py(msgspec.Structclasses). - The create-task → poll-result loop →
core/sio_captcha_instrument.py(sync) andcore/aio_captcha_instrument.py(async). - File/image preprocessing (base64 encoding, URL download) →
core/captcha_instrument.pyFileInstrument.
This is a library (SDK), so the primary flow is the user calling a solver class. Typical path for a captcha-solving call:
1. User instantiates a service class
from python3_capsolver.recaptcha import ReCaptcha
solver = ReCaptcha(api_key="CAI-...", captcha_type=CaptchaTypeEnm.ReCaptchaV2TaskProxyLess)
2. User calls captcha_handler() or aio_captcha_handler() with task-specific params
result = solver.captcha_handler(task_payload={"websiteURL": "...", "websiteKey": "..."})
3. CaptchaParams.captcha_handler() (core/base.py)
→ merges task_payload into self.task_params
→ creates SIOCaptchaInstrument(self) [or AIOCaptchaInstrument for async]
4. SIOCaptchaInstrument.processing_captcha() (core/sio_captcha_instrument.py)
→ builds RequestCreateTaskSer payload via msgspec Struct.to_dict()
→ POSTs to https://api.capsolver.com/createTask
→ if task is immediately ready: returns response
→ otherwise: enters polling loop
→ sleeps sleep_time seconds
→ POSTs to https://api.capsolver.com/getTaskResult
→ repeats up to 15 attempts (attempts_generator default)
→ returns on status "ready" or "failed"
5. Returns dict with full API response including solution
control.py follows a different, shorter path — it calls SIOCaptchaInstrument.send_post_request() or AIOCaptchaInstrument.send_post_request() directly for one-shot API calls like get_balance, bypassing the create-then-poll cycle (Observed: control.py lines 34–54, 49–54).
-
Rule: Service files must never import
requestsoraiohttpdirectly.- Rationale: All HTTP is encapsulated in the instrument layer; services are pure parameter holders.
- Enforcement / Signals (Observed): No service file (e.g.
recaptcha.py,cloudflare.py) contains an HTTP library import. Violation would be visible on review.
-
Rule: All serialization must use
msgspec.Structwithto_dict(), never thejsonmodule directly.- Rationale: Consistent serialization and type safety across the library.
- Enforcement / Signals (Observed):
core/serializer.pydefinesMyBaseModel(Struct)withto_dict(). All instruments call.to_dict()on structs.
-
Rule: Every captcha service must support both sync (
captcha_handler) and async (aio_captcha_handler) execution.- Rationale: The library's core value proposition is dual-mode operation.
- Enforcement / Signals (Observed): Both methods are defined in
CaptchaParams(core/base.py) and inherited by all service classes. Test suite includes paired sync/async tests.
-
Rule: Every service class must support context manager protocols (
with/async with).- Rationale: Resource cleanup pattern for library consumers.
- Enforcement / Signals (Observed):
CaptchaParamsinherits bothSIOContextManagerandAIOContextManagermixins fromcore/context_instr.py.
-
Rule: New captcha types must be registered in
CaptchaTypeEnm(core/enum.py).- Rationale: Single source of truth for type dispatch; the base class uses enum values to build API payloads.
- Enforcement / Signals (Observed):
core/base.pyconstructsTaskSer(type=captcha_type.value)from the enum.
-
Rule: Retry configuration is centralized in
core/const.py, not hardcoded in instruments.- Rationale: Single point of change for retry behavior across sync and async paths.
- Enforcement / Signals (Observed):
RETRIESandASYNC_RETRIESare defined inconst.pyand imported by both instruments andFileInstrument.
-
Rule: Dependency direction is strictly top-down: Service → Base → Instrument → Support.
- Rationale: Prevents circular dependencies and keeps the support layer reusable.
- Enforcement / Signals (Observed): Import statements in all files respect this direction. No file in
core/imports from a service file.
-
Rule:
__init__.pyfiles are intentionally empty (or export only__version__); users import via full path.- Rationale: Explicit imports avoid namespace pollution and circular re-exports.
- Enforcement / Signals (Observed):
src/python3_capsolver/__init__.pyexports__version__only;core/__init__.pyis empty. Docstrings show full-path imports.
-
Rule: Tests require
API_KEYenvironment variable and include rate-limiting delays.- Rationale: Integration tests hit the live Capsolver API; delays prevent throttling.
- Enforcement / Signals (Observed):
tests/conftest.pyreadsos.environ["API_KEY"]and definesdelay_func(1s) anddelay_class(2s) fixtures.
ARCHITECTURE.md (this file) is the global map of the repository: layers, dependency direction, invariants, and the code map. It answers "where is X?" and "what depends on what?".
Module-level detail lives in AGENTS.md files co-located with the code:
src/python3_capsolver/AGENTS.md— service-layer conventions, file listing, and per-service change rules.src/python3_capsolver/core/AGENTS.md— core module internals: instrument responsibilities, serialization patterns, and safe-change guidance.tests/AGENTS.md— test patterns, fixtures, and how to add tests for new services.
API documentation is generated by Sphinx from docs/ (Observed: docs/conf.py, docs/Makefile). Build with make doc.
Build, test, and lint commands are documented in the root Makefile and in AGENTS.md at repository root. The root AGENTS.md also contains a condensed version of the architecture summary and validation commands.
What belongs where:
- Global architecture (this file): layers, boundaries, invariants, physical layout, primary data flow.
- Module
AGENTS.md: local file listing, local boundaries, and specific change rules for that module. - Sphinx
docs/: public API reference, usage examples, and user-facing guides.