unicaptcha
Universal Python interface to multiple anti-captcha services.
Status: highly experimental. Pre-1.0. No public API stability is promised, even for the documented surface. Anything may change between releases.
Documentation: https://lorien.github.io/unicaptcha/
Supported services
| Provider | Kind string | Default base URL |
|---|---|---|
| 2Captcha (modern JSON API) | twocaptcha |
https://api.2captcha.com |
| Anti-Captcha | anti-captcha |
https://api.anti-captcha.com |
| CapMonster Cloud | capmonster |
https://api.capmonster.cloud |
| Capsolver | capsolver |
https://api.capsolver.com |
2Captcha-protocol mirrors such as RuCaptcha work by overriding the base URL
(RuCaptcha's JSON API v2 is verified complete): TwoCaptchaClient(api_key=..., base_url="https://rucaptcha.com"). Smaller mirrors need per-service
verification of their JSON API.
Supported CAPTCHA kinds (v1)
| Kind | Challenge base | Solution base |
|---|---|---|
| Image CAPTCHA | ImageChallenge |
ImageSolution |
| Text CAPTCHA | TextChallenge |
TextSolution |
| reCAPTCHA v2 | RecaptchaV2Challenge |
RecaptchaV2Solution |
| reCAPTCHA v3 | RecaptchaV3Challenge |
RecaptchaV3Solution |
| hCaptcha | HCaptchaChallenge |
HCaptchaSolution |
| FunCaptcha / Arkose | FunCaptchaChallenge |
FunCaptchaSolution |
| GeeTest v3 | GeeTestV3Challenge |
GeeTestV3Solution |
| GeeTest v4 | GeeTestV4Challenge |
GeeTestV4Solution |
| Cloudflare Turnstile | TurnstileChallenge |
TurnstileSolution |
Kind coverage varies by provider (e.g. text is 2Captcha + Anti-Captcha
only); unsupported kinds raise UnsupportedChallengeError.
Install
Not yet published to PyPI — install from the repository:
uv add git+https://github.com/lorien/unicaptcha
or pip install git+https://github.com/lorien/unicaptcha. Once published,
the plain uv add unicaptcha works. Requires Python 3.11+. Single runtime
dependency: httpx.
Usage
Universal client
The universal client registers one or more provider adapters and dispatches each challenge to the adapter that supports it.
from pathlib import Path
from unicaptcha import Solver, ImageChallenge
from unicaptcha.provider.twocaptcha import TwoCaptchaAdapter
client = Solver(adapters=[TwoCaptchaAdapter("YOUR_API_KEY")])
result = client.solve(ImageChallenge(Path("captcha.png")))
print(result.solution.text) # the solved captcha text
A challenge is a frozen dataclass describing what to solve. The kind-base
classes (ImageChallenge, RecaptchaV2Challenge, …) carry only the fields
every provider shares; the concrete provider classes
(TwoCaptchaImageChallenge, …) add provider-specific options.
- A kind-base challenge routes to any registered adapter supporting the
kind — pass
provider="twocaptcha"to pin one, or omit it for a uniform random pick among the supporting adapters. - Provider extras use the concrete class, e.g.
TwoCaptchaImageChallenge(body, numeric=True, min_len=4). - Image bodies accept
bytesor aPath; the value is normalized to bytes at construction.
Provider facades
For a single provider, a facade client offers one convenience method per kind with full parameter parity:
import asyncio
from unicaptcha.provider.twocaptcha import AsyncTwoCaptchaClient, TwoCaptchaClient
with TwoCaptchaClient("YOUR_API_KEY") as client:
result = client.solve_image(b"captcha.png", numeric=1)
async def main() -> None:
async with AsyncTwoCaptchaClient("YOUR_API_KEY") as client:
result = await client.solve_recaptcha_v2(
sitekey="SITEKEY", pageurl="https://example.com"
)
print(result.solution.token)
asyncio.run(main())
Each provider package exports <Provider>Client and Async<Provider>Client
(TwoCaptchaClient, AntiCaptchaClient, CapMonsterClient,
CapsolverClient, and their async counterparts). Facade constructors take
api_key positionally and otherwise mirror Solver minus adapters
(base_url, referral, proxy, time, retry, network, on_event).
Two-phase batch
submit() splits solving from collecting: it returns a TaskTicket, which
you can persist (via its task_ref) and collect later.
from unicaptcha import ImageChallenge, TaskRef
ticket = client.submit(ImageChallenge(Path("a.png"))) # collect later
# ... later ...
result = client.wait(ticket) # -> TaskResult, typed
status = client.wait_ref(TaskRef("twocaptcha", 12345), timeout=120) # from a persisted id
Auxiliary operations
The universal client and the facades share the same aux names:
get_balance(provider)→Decimalbalance in USD (facades take no argument)get_task_status(task)→ one-shot status (TaskRef, orinton facades)report_bad_result(task)/report_good_result(task)→bool(coverage varies by provider)get_abandoned_tasks()→ tasks cancelled while solving
Errors
Every library exception derives from UnicaptchaError and carries a
kind: ErrorKind plus the verbatim provider response in raw_response:
NoSolutionError, TaskTimeoutError, RateLimitError, ServiceBusyError,
InsufficientBalanceError, AuthenticationError, NetworkError,
ProviderError, InvalidConfigError, InvalidChallengeError,
UnsupportedChallengeError, ClientClosedError.
Events
Pass on_event= at construction or per call to observe the task lifecycle
(SUBMIT_REQUESTED, SUBMIT_ACCEPTED, RESULT_RECEIVED, …) as typed
TaskEvents.
Examples
Runnable scripts, one per use case in examples/sync/ and examples/async/:
every captcha kind, two-phase batch, aux ops, events, errors, proxy.
See examples/README.md.
Custom providers
unicaptcha ships a public adapter SDK: third parties can implement their own
provider adapters (BaseAdapter) and register them in the universal client.
The test suite includes a reference third-party adapter, MyServiceAdapter
(tests/_myservice.py), written against the public API only — the pattern to
follow. See spec/docs/architecture.md ("Adapter SDK") for the contract.
Funding
The built-in adapters embed unicaptcha's referral ID in every request by
default; the provider pays the project a small commission per solve at no
change to your pricing. Pass referral=False to disable it, or
referral="your-own-id" to credit your own software registration.
Third-party adapters embed nothing by default.
License
MIT. Repository: https://github.com/lorien/unicaptcha
Metadata
Release files for unicaptcha 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| unicaptcha-0.1.0.tar.gz | 276.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| unicaptcha-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 371.5 kB
Release files / unicaptcha-0.1.0.tar.gz
| Download URL | unicaptcha-0.1.0.tar.gz |
|---|---|
| Size | 276.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4c775dcf209a92a6a1b85244a75634e8ca19ed0add2a328efb4cf917e7055290
|
|
BLAKE2b-256 checksum How to use checksums |
15049e1cabd3f7acbb21bb786ccc918a98fccb72838c7f74f6264da83079653e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency logRelease files / unicaptcha-0.1.0-py3-none-any.whl
| Download URL | unicaptcha-0.1.0-py3-none-any.whl |
|---|---|
| Size | 94.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7879304a44a66c50a5f44431b92d413f1f67d0bb806b7b0964b0496e4db5d257
|
|
BLAKE2b-256 checksum How to use checksums |
9dc13a75177905df6e439863a7b7413466991eb3a49c9b4f3759a93875142d46
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency logSecurity for unicaptcha 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for unicaptcha-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.