captcha-solver-api 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,730 @@
1
+ Metadata-Version: 2.4
2
+ Name: captcha-solver-api
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for solving reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest v3/v4, Yandex SmartCaptcha, Tencent, and image/click captchas via the Captcha Solver API
5
+ Author: Captcha Solver Team
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://captcha-solver.com
8
+ Project-URL: Documentation, https://captcha-solver.com/en/docs/captcha-types
9
+ Project-URL: Repository, https://github.com/captcha-solver-api/python-sdk
10
+ Keywords: captcha,captcha solver,recaptcha,recaptcha v2,recaptcha v3,cloudflare turnstile,geetest,geetest v4,yandex smartcaptcha,tencent captcha,image captcha,coordinates,click captcha,api
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Internet
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE.md
28
+ Requires-Dist: requests>=2.28
29
+ Requires-Dist: httpx>=0.24
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7; extra == "dev"
32
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
33
+ Requires-Dist: pytest-mock>=3; extra == "dev"
34
+ Requires-Dist: python-dotenv>=1.0; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # Captcha Solver Python SDK
38
+
39
+ ![python-sdk-banner](https://raw.githubusercontent.com/captcha-solver-api/python-sdk/main/assets/repo-banner-python.png)
40
+
41
+ Official Python SDK for the Captcha Solver API. Solve reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest, Yandex SmartCaptcha, Tencent, and image/click captchas with a single method call -- sync or async.
42
+
43
+ Full API reference (all endpoints, error codes, captcha-type details): **https://captcha-solver.com/en/docs/captcha-types**
44
+
45
+ ## Table of Contents
46
+
47
+ - [Installation](#installation)
48
+ - [Configuration](#configuration)
49
+ - [Quick Start](#quick-start)
50
+ - [Supported CAPTCHA Types](#supported-captcha-types)
51
+ - [Client Reference](#client-reference)
52
+ - [CaptchaClient(...)](#captchaclient)
53
+ - [solve(task, language_pool=None, timeout=None)](#solvetask-language_poolnone-timeoutnone)
54
+ - [create_task(task, language_pool=None)](#create_tasktask-language_poolnone)
55
+ - [get_task_result(task_id)](#get_task_resulttask_id)
56
+ - [get_balance()](#get_balance)
57
+ - [Captcha Types](#captcha-types)
58
+ - [reCAPTCHA v2](#recaptcha-v2)
59
+ - [reCAPTCHA v2 Enterprise](#recaptcha-v2-enterprise)
60
+ - [reCAPTCHA v3](#recaptcha-v3)
61
+ - [Cloudflare Turnstile](#cloudflare-turnstile)
62
+ - [Image to Text](#image-to-text)
63
+ - [GeeTest (v3 & v4)](#geetest-v3--v4)
64
+ - [Yandex SmartCaptcha](#yandex-smartcaptcha)
65
+ - [Coordinates (click captcha)](#coordinates-click-captcha)
66
+ - [Tencent](#tencent)
67
+ - [Advanced Usage](#advanced-usage)
68
+ - [Check balance](#check-balance)
69
+ - [Custom timeout and polling](#custom-timeout-and-polling)
70
+ - [Worker language pool](#worker-language-pool)
71
+ - [Async client](#async-client)
72
+ - [Solving multiple captchas in parallel](#solving-multiple-captchas-in-parallel)
73
+ - [Error handling](#error-handling)
74
+ - [Running the examples](#running-the-examples)
75
+ - [Requirements](#requirements)
76
+ - [API Documentation](#api-documentation)
77
+ - [License](#license)
78
+
79
+ ## Installation
80
+
81
+ ```bash
82
+ pip install captcha-solver-api
83
+ ```
84
+
85
+ Or install the latest version from GitHub:
86
+
87
+ ```bash
88
+ pip install git+https://github.com/captcha-solver-api/python-sdk.git
89
+ ```
90
+
91
+ ## Configuration
92
+
93
+ The client always takes the API key as an explicit argument -- it does not read
94
+ environment variables on its own. Read `CAPTCHA_API_KEY` yourself and pass it in:
95
+
96
+ ```bash
97
+ export CAPTCHA_API_KEY=your_api_key
98
+ ```
99
+
100
+ ```python
101
+ import os
102
+ from captcha_solver_api import CaptchaClient
103
+ client = CaptchaClient(os.getenv("CAPTCHA_API_KEY"))
104
+ ```
105
+ Or just pass the key directly, without an environment variable:
106
+
107
+ ```python
108
+ client = CaptchaClient("your_api_key")
109
+ ```
110
+
111
+ ## Quick Start
112
+
113
+ Solve a reCAPTCHA v2 in 4 lines.
114
+
115
+ ```python
116
+ from captcha_solver_api import CaptchaClient
117
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
118
+ client = CaptchaClient("your_api_key")
119
+ task = RecaptchaV2TaskProxyless(
120
+ websiteURL="https://example.com/login",
121
+ websiteKey="YOUR_WEBSITE_KEY"
122
+ )
123
+ result = client.solve(task)
124
+ print(result["gRecaptchaResponse"])
125
+ ```
126
+
127
+ ## Supported CAPTCHA Types
128
+
129
+ | Type | Proxyless | With Proxy |
130
+ |---|---|---|
131
+ | reCAPTCHA v2 | ✅ | ✅ |
132
+ | reCAPTCHA v2 Enterprise | ✅ | ✅ |
133
+ | reCAPTCHA v3 | ✅ | ❌ |
134
+ | Cloudflare Turnstile | ✅ | ✅ |
135
+ | GeeTest v3 | ✅ | ✅ |
136
+ | GeeTest v4 | ✅ | ✅ |
137
+ | Image to Text | ✅ | ❌ |
138
+ | Yandex SmartCaptcha | ✅ | ✅ |
139
+ | Coordinates (click captcha) | ✅ | ❌ |
140
+ | Tencent | ✅ | ✅ |
141
+
142
+ ## Client Reference
143
+
144
+ Every method below is available on both `CaptchaClient` (sync, `requests`-based) and
145
+ `AsyncCaptchaClient` (async, `httpx`-based, same names, `await`ed). Full docstrings
146
+ with the same content live in [captcha_solver_api/client.py](https://github.com/captcha-solver-api/python-sdk/blob/main/captcha_solver_api/client.py),
147
+ [captcha_solver_api/async_client.py](https://github.com/captcha-solver-api/python-sdk/blob/main/captcha_solver_api/async_client.py), and
148
+ [captcha_solver_api/tasks.py](https://github.com/captcha-solver-api/python-sdk/blob/main/captcha_solver_api/tasks.py) -- this section mirrors them for quick
149
+ reference without leaving the README.
150
+
151
+ ### `CaptchaClient(...)`
152
+
153
+ Constructor.
154
+
155
+ | Parameter | Type | Default | Description |
156
+ |---|---|---|---|
157
+ | `client_key` | `str` | required | Your Captcha Solver API key. Raises `ValidationError` if empty. |
158
+ | `base_url` | `str` | `https://api.captcha-solver.com` | API base URL. Override only for self-hosted/staging deployments. |
159
+ | `timeout` | `int` | `120` | Default max seconds `solve()` waits for a solution before raising `CaptchaTimeoutError`. Overridable per call. |
160
+ | `polling_interval` | `int` | `3` | Seconds between `getTaskResult` polls inside `solve()`. |
161
+ | `language_pool` | `Optional[str]` | `None` | Default worker pool (`"en"` or `"ru"`) applied to every call that doesn't pass its own `language_pool`. |
162
+
163
+ Both clients hold a reusable connection pool (`requests.Session` / `httpx.AsyncClient`)
164
+ for their lifetime instead of opening one per request. Close it when you're done --
165
+ `client.close()` (sync) or `await client.aclose()` (async) -- or use either client as
166
+ a context manager:
167
+
168
+ ```python
169
+ with CaptchaClient("your_api_key") as client:
170
+ result = client.solve(task)
171
+
172
+ async with AsyncCaptchaClient("your_api_key") as client:
173
+ result = await client.solve(task)
174
+ ```
175
+
176
+ ### `solve(task, language_pool=None, timeout=None)`
177
+
178
+ The main entry point. Submits `task`, polls until it's solved, and returns the
179
+ solution -- wraps `create_task()` + `get_task_result()` so you don't poll by hand.
180
+
181
+ | Parameter | Type | Description |
182
+ |---|---|---|
183
+ | `task` | task object | One of the classes from `captcha_solver_api.tasks` (see [Captcha Types](#captcha-types)). |
184
+ | `language_pool` | `Optional[str]` | Worker pool selector, `"en"` or `"ru"`. |
185
+ | `timeout` | `Optional[int]` | Overrides the client's default timeout for this call only, in seconds. Useful for captcha types that reliably take longer (e.g. classic reCAPTCHA v2, GeeTest, reCAPTCHA v3 with a high `minScore`). |
186
+
187
+ Returns the `solution` dict once `status` is `"ready"` -- its shape depends on
188
+ the task type (see [Captcha Types](#captcha-types)).
189
+ Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
190
+
191
+ ### `create_task(task, language_pool=None)`
192
+
193
+ Submits `task` and returns its numeric task ID without waiting for a solution.
194
+ Same parameters as `solve()`. Use this instead of `solve()` only if you need to
195
+ manage polling yourself (e.g. checking on many tasks from a different process).
196
+ Raises `ApiError`, `NetworkError`.
197
+
198
+ ### `get_task_result(task_id)`
199
+
200
+ Fetches the current status of a task created with `create_task()`. Always
201
+ returns a dict with a `status` key (`"processing"` or `"ready"`); when
202
+ `"ready"`, also has a `solution` dict. This is a single poll, not a wait --
203
+ call it repeatedly (as `solve()` does) until `status` is `"ready"`.
204
+ Raises `ApiError`, `NetworkError`.
205
+
206
+ ### `get_balance()`
207
+
208
+ Returns the account's current balance (`float`) in the account's currency.
209
+ Raises `ApiError`, `NetworkError`.
210
+
211
+ ## Captcha Types
212
+
213
+ Each section below covers one captcha type end-to-end: task parameters, the
214
+ `solution` shape, a runnable example, and a link to the full spec. Optional
215
+ fields left unset are omitted from the request. Every code block matches a
216
+ runnable file under [examples/sync](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/sync) (and its
217
+ [examples/async](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/async) counterpart) -- swap the placeholder
218
+ `websiteURL`/`websiteKey`/etc. for values from your own target page before
219
+ running. See [Running the examples](#running-the-examples) for details.
220
+
221
+ Types with a `*Task` counterpart (as opposed to `*TaskProxyless`) also accept
222
+ `proxyType` / `proxyAddress` / `proxyPort` / `proxyLogin` / `proxyPassword` to
223
+ solve through your own proxy instead of the service's IPs.
224
+
225
+ ### reCAPTCHA v2
226
+
227
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#recaptcha-v2)</sup>
228
+
229
+ Use this method to solve reCAPTCHA v2 and obtain a token for the target page.
230
+ Choose the proxy variant when the solving session must use your own IP address.
231
+
232
+ `RecaptchaV2TaskProxyless` (no proxy) / `RecaptchaV2Task` (with proxy).
233
+
234
+ | Parameter | Required | Description |
235
+ |---|---|---|
236
+ | `websiteURL` | yes | Full URL of the page where the captcha is located. |
237
+ | `websiteKey` | yes | Value of the widget's `data-sitekey` attribute. |
238
+ | `isInvisible` | no | `True` for invisible reCAPTCHA v2. |
239
+ | `recaptchaDataSValue` | no | The `data-s` value, found on Google Search/YouTube pages. |
240
+ | `apiDomain` | no | Non-default domain the widget's script is served from, if any. |
241
+ | `userAgent` | no | User-Agent to solve with. Recommended to match the agent submitting the token. |
242
+ | `cookies` | no | Session cookies to use while solving, if the page requires them. |
243
+
244
+ **Response:** `gRecaptchaResponse` -- submit as `g-recaptcha-response`.
245
+
246
+ ```python
247
+ from captcha_solver_api import CaptchaClient
248
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
249
+ client = CaptchaClient("your_api_key")
250
+ task = RecaptchaV2TaskProxyless(
251
+ websiteURL="https://example.com/login",
252
+ websiteKey="YOUR_WEBSITE_KEY"
253
+ )
254
+ result = client.solve(task)
255
+ print(result["gRecaptchaResponse"])
256
+ ```
257
+
258
+ With proxy, use `RecaptchaV2Task` instead:
259
+
260
+ ```python
261
+ task = RecaptchaV2Task(
262
+ websiteURL="https://example.com/login",
263
+ websiteKey="YOUR_WEBSITE_KEY",
264
+ proxyType="http",
265
+ proxyAddress="1.2.3.4",
266
+ proxyPort=8080,
267
+ proxyLogin="user",
268
+ proxyPassword="password"
269
+ )
270
+ ```
271
+
272
+ ### reCAPTCHA v2 Enterprise
273
+
274
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#recaptcha-v2-enterprise)</sup>
275
+
276
+ Use this method to solve the Enterprise version of reCAPTCHA v2 and obtain a
277
+ token for a page that uses `grecaptcha.enterprise`.
278
+
279
+ `RecaptchaV2EnterpriseTaskProxyless` / `RecaptchaV2EnterpriseTask`. Same fields
280
+ as reCAPTCHA v2, plus:
281
+
282
+ | Parameter | Required | Description |
283
+ |---|---|---|
284
+ | `enterprisePayload` | no | Extra parameters passed to `grecaptcha.enterprise.render` on the page, e.g. `{"s": "..."}`. |
285
+ | `apiDomain` | no | Defaults to `google.com`. |
286
+
287
+ **Response:** `gRecaptchaResponse`.
288
+
289
+ ```python
290
+ from captcha_solver_api import CaptchaClient
291
+ from captcha_solver_api.tasks import RecaptchaV2EnterpriseTaskProxyless
292
+ client = CaptchaClient("your_api_key")
293
+ task = RecaptchaV2EnterpriseTaskProxyless(
294
+ websiteURL="https://example.com/login",
295
+ websiteKey="YOUR_WEBSITE_KEY"
296
+ )
297
+ result = client.solve(task)
298
+ print(result["gRecaptchaResponse"])
299
+ ```
300
+
301
+ With proxy, use `RecaptchaV2EnterpriseTask` (same proxy fields as reCAPTCHA v2).
302
+
303
+ ### reCAPTCHA v3
304
+
305
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#recaptcha-v3)</sup>
306
+
307
+ Use this method to obtain a score-based reCAPTCHA v3 token for a specific site,
308
+ action, and minimum score. This variant does not use a proxy.
309
+
310
+ `RecaptchaV3TaskProxyless`. No proxy variant exists -- v3 is score-based and
311
+ invisible, so there's no widget/session to pin to a proxy IP.
312
+
313
+ | Parameter | Required | Description |
314
+ |---|---|---|
315
+ | `websiteURL` | yes | Full URL of the page where the captcha is located. |
316
+ | `websiteKey` | yes | Site key for the v3 widget. |
317
+ | `minScore` | yes | Minimum acceptable token score to return, e.g. `0.3`, `0.7`, `0.9`. |
318
+ | `pageAction` | no | The `action` parameter passed to `grecaptcha.execute()` on the page. |
319
+ | `isEnterprise` | no | `True` for reCAPTCHA v3 Enterprise. |
320
+ | `apiDomain` | no | Non-standard domain the widget's script is served from, if any. |
321
+
322
+ **Response:** `gRecaptchaResponse`.
323
+
324
+ ```python
325
+ from captcha_solver_api import CaptchaClient
326
+ from captcha_solver_api.tasks import RecaptchaV3TaskProxyless
327
+ client = CaptchaClient("your_api_key")
328
+ task = RecaptchaV3TaskProxyless(
329
+ websiteURL="https://example.com/login",
330
+ websiteKey="YOUR_WEBSITE_KEY",
331
+ minScore=0.3,
332
+ pageAction="homepage"
333
+ )
334
+ result = client.solve(task)
335
+ print(result["gRecaptchaResponse"])
336
+ ```
337
+
338
+ ### Cloudflare Turnstile
339
+
340
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#cloudflare-turnstile)</sup>
341
+
342
+ Use this method to solve a Cloudflare Turnstile widget and obtain the token
343
+ that the target page expects in `cf-turnstile-response`.
344
+
345
+ `TurnstileTaskProxyless` / `TurnstileTask`.
346
+
347
+ | Parameter | Required | Description |
348
+ |---|---|---|
349
+ | `websiteURL` | yes | Full URL of the page where the widget is located. |
350
+ | `websiteKey` | yes | Value of the widget's `data-sitekey` attribute. |
351
+ | `action` | no | Value of the widget's `data-action` attribute, if set. |
352
+ | `data` | no | Custom payload from the widget's `data-cdata` attribute, if set. |
353
+ | `pagedata` | no | Value of the `chlPageData` parameter, needed for some Cloudflare challenge pages beyond the basic widget. |
354
+ | `userAgent` | no | User-Agent to solve with -- the returned token is tied to it, submit with the same one. |
355
+
356
+ **Response:** `token` -- submit as `cf-turnstile-response`.
357
+
358
+ ```python
359
+ from captcha_solver_api import CaptchaClient
360
+ from captcha_solver_api.tasks import TurnstileTaskProxyless
361
+ client = CaptchaClient("your_api_key")
362
+ task = TurnstileTaskProxyless(
363
+ websiteURL="https://example.com/login",
364
+ websiteKey="YOUR_WEBSITE_KEY"
365
+ )
366
+ result = client.solve(task)
367
+ print(result["token"])
368
+ ```
369
+
370
+ With proxy, use `TurnstileTask` (same proxy fields as reCAPTCHA v2).
371
+
372
+ ### Image to Text
373
+
374
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#image-to-text)</sup>
375
+
376
+ Use this method to recognize text, numbers, or simple math expressions in an
377
+ image captcha. The image is sent directly and does not require a proxy.
378
+
379
+ `ImageToTextTask`. No proxy variant -- the image is submitted directly, no
380
+ browser session involved.
381
+
382
+ | Parameter | Required | Description |
383
+ |---|---|---|
384
+ | `body` | yes | The captcha image, base64-encoded (no `data:image/...;base64,` prefix). |
385
+ | `phrase` | no | `True` if the answer is multiple words. |
386
+ | `case` | no | `True` if the answer is case-sensitive. |
387
+ | `numeric` | no | `0` unspecified, `1` digits only, `2` letters only, `3` any with digits, `4` any with letters. |
388
+ | `math` | no | `True` if the image contains a math expression to evaluate. |
389
+ | `minLength` / `maxLength` | no | Expected answer length bounds. |
390
+ | `comment` | no | Free-text hint for the worker. |
391
+ | `imgInstructions` | no | Optional supplementary instruction image, base64-encoded. |
392
+
393
+ **Response:** `text` -- the recognized text/answer.
394
+
395
+ ```python
396
+ from captcha_solver_api import CaptchaClient
397
+ from captcha_solver_api.tasks import ImageToTextTask
398
+ import base64
399
+ with open("examples/assets/captcha-digits.png", "rb") as f:
400
+ image_base64 = base64.b64encode(f.read()).decode("utf-8")
401
+ client = CaptchaClient("your_api_key")
402
+ task = ImageToTextTask(
403
+ body=image_base64,
404
+ numeric=1,
405
+ minLength=4,
406
+ maxLength=6
407
+ )
408
+ result = client.solve(task)
409
+ print(result["text"])
410
+ ```
411
+
412
+ ### GeeTest (v3 & v4)
413
+
414
+ <sup>[API method description: v3](https://captcha-solver.com/en/docs/captcha-types#geetest-v3), [v4](https://captcha-solver.com/en/docs/captcha-types#geetest-v4)</sup>
415
+
416
+ Use this method to solve GeeTest puzzle captchas. Select version 3 or 4 and
417
+ pass the values collected from the target page before creating the task.
418
+
419
+ `GeeTestTaskProxyless` / `GeeTestTask`. Set `version=4` for v4 (with
420
+ `initParameters["captcha_id"]`); v3 is the default and needs `gt`/`challenge` instead.
421
+
422
+ | Parameter | Required | Description |
423
+ |---|---|---|
424
+ | `websiteURL` | yes | Full URL of the page where the widget is located. |
425
+ | `version` | no | `3` (default) or `4`. |
426
+ | `gt` | v3 only | Public key of the GeeTest widget. |
427
+ | `challenge` | v3 only | Session-specific challenge value from the page -- must be freshly fetched for every request, it cannot be reused. |
428
+ | `initParameters` | v4 only | Extra parameters from the page's `initGeetest` call; for v4 must contain `captcha_id`. |
429
+ | `geetestApiServerSubdomain` | no | Custom GeeTest API subdomain, if the site uses one. |
430
+ | `userAgent` | no | User-Agent to solve with. |
431
+ | `risk_type` | no | Value of the `risk_type` parameter from the captcha-loading request, if present. Dynamic, single-use, and time-limited. |
432
+
433
+ **Response:** v3 -- `challenge`, `validate`, `seccode`. v4 -- `captcha_id`, `lot_number`, `pass_token`, `gen_time`, `captcha_output`.
434
+ Docs: [v3 ↗](https://captcha-solver.com/en/docs/captcha-types#geetest-v3), [v4 ↗](https://captcha-solver.com/en/docs/captcha-types#geetest-v4)
435
+
436
+ ```python
437
+ from captcha_solver_api import CaptchaClient
438
+ from captcha_solver_api.tasks import GeeTestTaskProxyless
439
+ client = CaptchaClient("your_api_key")
440
+ task = GeeTestTaskProxyless(
441
+ websiteURL="https://example.com/login",
442
+ gt="f2ae6cadcf7886856696c46d84d109d1",
443
+ challenge="12345678abc90123d45678e90123f45g6" # dynamic -- fetch a fresh one per request
444
+ )
445
+ result = client.solve(task)
446
+ print(result["validate"])
447
+ print(result["seccode"])
448
+ ```
449
+ `challenge` is session-specific and expires quickly, so it can't be hardcoded
450
+ into a static example -- see [examples/sync/geetest_v3.py](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/sync/geetest_v3.py)
451
+ for where the fetch belongs in the flow.
452
+
453
+ ```python
454
+ task = GeeTestTaskProxyless(
455
+ websiteURL="https://example.com/login",
456
+ version=4,
457
+ initParameters={"captcha_id": "YOUR_CAPTCHA_ID"}
458
+ )
459
+ result = client.solve(task)
460
+ print(result["captcha_output"])
461
+ ```
462
+
463
+ With proxy, use `GeeTestTask` (same proxy fields as reCAPTCHA v2).
464
+
465
+ ### Yandex SmartCaptcha
466
+
467
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#yandex-smartcaptcha)</sup>
468
+
469
+ Use this method to solve the token-based Yandex SmartCaptcha and obtain a token
470
+ for the widget on the target page. Use the coordinates method for image challenges.
471
+
472
+ `YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based
473
+ challenge. For the image challenge instead, use `CoordinatesTask` with
474
+ `imgType="smart_captcha"` (see [Coordinates](#coordinates-click-captcha) below).
475
+
476
+ | Parameter | Required | Description |
477
+ |---|---|---|
478
+ | `websiteURL` | yes | Full URL of the page where the widget is located. |
479
+ | `websiteKey` | yes | The `sitekey` value from the page source or captcha iframe. |
480
+ | `userAgent` | no | User-Agent to solve with. |
481
+ | `cookies` | no | Session cookies to use while solving, if the page requires them. |
482
+
483
+ Proxy variant note: `proxyType` also accepts `"https"` for this captcha type
484
+ only (in addition to `http`/`socks4`/`socks5`).
485
+
486
+ **Response:** `token`.
487
+
488
+ ```python
489
+ from captcha_solver_api import CaptchaClient
490
+ from captcha_solver_api.tasks import YandexSmartCaptchaTaskProxyless
491
+ client = CaptchaClient("your_api_key")
492
+ task = YandexSmartCaptchaTaskProxyless(
493
+ websiteURL="https://example.com/login",
494
+ websiteKey="YOUR_WEBSITE_KEY"
495
+ )
496
+ result = client.solve(task)
497
+ print(result["token"])
498
+ ```
499
+
500
+ With proxy, use `YandexSmartCaptchaTask` (same proxy fields as reCAPTCHA v2,
501
+ plus the `https` option above).
502
+
503
+ ### Coordinates (click captcha)
504
+
505
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#coordinates)</sup>
506
+
507
+ Use this method to identify points that a worker should click in an image. It
508
+ supports generic click captchas and the image version of Yandex SmartCaptcha.
509
+
510
+ `CoordinatesTask`. Used both for generic "click on X" captchas and for Yandex
511
+ SmartCaptcha's image challenge. No proxy variant -- the image is submitted directly.
512
+
513
+ | Parameter | Required | Description |
514
+ |---|---|---|
515
+ | `body` | yes | The captcha image, base64-encoded. |
516
+ | `comment` | no (recommended) | Hint for the worker, e.g. `"click on the green apple"`. |
517
+ | `imgInstructions` | required for `imgType="smart_captcha"` | Instruction image, base64-encoded, showing what to click and in what order. |
518
+ | `minClicks` | no | Minimum number of clicks expected (default `1`). |
519
+ | `maxClicks` | no | Maximum number of clicks allowed. |
520
+ | `imgType` | no | `"smart_captcha"` to solve a Yandex SmartCaptcha image challenge instead of a generic click captcha. |
521
+
522
+ **Response:** `coordinates` -- a list of `{"x": int, "y": int}` pixel positions to click, in order.
523
+
524
+ ```python
525
+ from captcha_solver_api import CaptchaClient
526
+ from captcha_solver_api.tasks import CoordinatesTask
527
+ import base64
528
+ with open("examples/assets/fruit-click.png", "rb") as f:
529
+ image_base64 = base64.b64encode(f.read()).decode("utf-8")
530
+ client = CaptchaClient("your_api_key")
531
+ task = CoordinatesTask(
532
+ body=image_base64,
533
+ comment="click on the green apple"
534
+ )
535
+ result = client.solve(task)
536
+ print(result["coordinates"]) # [{"x": 140, "y": 110}]
537
+ ```
538
+ For the Yandex SmartCaptcha image challenge, see
539
+ [examples/sync/yandex_smartcaptcha_image.py](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/sync/yandex_smartcaptcha_image.py)
540
+ (or [examples/async](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/async/yandex_smartcaptcha_image.py)).
541
+
542
+ ### Tencent
543
+
544
+ <sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#tencent)</sup>
545
+
546
+ Use this method to solve Tencent Captcha and obtain the ticket and callback
547
+ values required by the target page.
548
+
549
+ `TencentTaskProxyless` / `TencentTask`.
550
+
551
+ | Parameter | Required | Description |
552
+ |---|---|---|
553
+ | `websiteURL` | yes | Full URL of the page where the captcha is located. |
554
+ | `appId` | yes | Value of the `appId` parameter found in the page source. |
555
+ | `captchaScript` | no | URL of the Tencent captcha script, if the page uses a non-default one. |
556
+
557
+ **Response:** `appid`, `ret`, `ticket`, `randstr` -- pass all four into the page's Tencent captcha callback.
558
+
559
+ ```python
560
+ from captcha_solver_api import CaptchaClient
561
+ from captcha_solver_api.tasks import TencentTaskProxyless
562
+ client = CaptchaClient("your_api_key")
563
+ task = TencentTaskProxyless(
564
+ websiteURL="https://example.com/register",
565
+ appId="YOUR_APP_ID"
566
+ )
567
+ result = client.solve(task)
568
+ print(result["ticket"])
569
+ ```
570
+
571
+ With proxy, use `TencentTask` (same proxy fields as reCAPTCHA v2).
572
+
573
+ ## Advanced Usage
574
+
575
+ ### Check balance
576
+
577
+ ```python
578
+ from captcha_solver_api import CaptchaClient
579
+ client = CaptchaClient("your_api_key")
580
+ balance = client.get_balance()
581
+ print(f"Balance: {balance}")
582
+ ```
583
+
584
+ ### Custom timeout and polling
585
+
586
+ ```python
587
+ client = CaptchaClient(
588
+ client_key="your_api_key",
589
+ timeout=180,
590
+ polling_interval=5
591
+ )
592
+ ```
593
+ A single `solve()` call can also override the client's default timeout, which is handy for
594
+ captcha types that reliably take longer to solve (e.g. classic reCAPTCHA v2) without changing
595
+ it for every other call:
596
+
597
+ ```python
598
+ result = client.solve(task, timeout=300)
599
+ ```
600
+
601
+ ### Worker language pool
602
+
603
+ Set a default `language_pool` once at construction instead of passing it to every call:
604
+
605
+ ```python
606
+ client = CaptchaClient(client_key="your_api_key", language_pool="en")
607
+ result = client.solve(task) # uses the "en" pool
608
+ result = client.solve(task, language_pool="ru") # overrides it just for this call
609
+ ```
610
+
611
+ ### Async client
612
+
613
+ `AsyncCaptchaClient` mirrors `CaptchaClient` method-for-method (`create_task`, `get_task_result`,
614
+ `get_balance`, `solve`, same constructor options), just `await`ed and built on `httpx` instead of
615
+ `requests`. It keeps one `httpx.AsyncClient` connection pool open for its whole lifetime, so
616
+ concurrent `solve()` calls (see below) and repeated polling share keep-alive connections instead
617
+ of each opening a new one:
618
+
619
+ ```python
620
+ import asyncio
621
+ from captcha_solver_api import AsyncCaptchaClient
622
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
623
+
624
+ async def main():
625
+ client = AsyncCaptchaClient("your_api_key")
626
+ task = RecaptchaV2TaskProxyless(
627
+ websiteURL="https://example.com/login",
628
+ websiteKey="YOUR_WEBSITE_KEY"
629
+ )
630
+ result = await client.solve(task)
631
+ print(result["gRecaptchaResponse"])
632
+
633
+ asyncio.run(main())
634
+ ```
635
+ See [examples/async](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/async) for every captcha type in async form.
636
+
637
+ ### Solving multiple captchas in parallel
638
+
639
+ This is the main reason to reach for the async client -- run several `solve()` calls
640
+ concurrently instead of waiting for each one in turn:
641
+
642
+ ```python
643
+ import asyncio
644
+ from captcha_solver_api import AsyncCaptchaClient
645
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless, TurnstileTaskProxyless
646
+
647
+ async def solve_multiple():
648
+ client = AsyncCaptchaClient("your_api_key")
649
+
650
+ task1 = client.solve(RecaptchaV2TaskProxyless(websiteURL="https://site1.com", websiteKey="key1"))
651
+ task2 = client.solve(TurnstileTaskProxyless(websiteURL="https://site2.com", websiteKey="key2"))
652
+
653
+ results = await asyncio.gather(task1, task2, return_exceptions=True)
654
+ return results
655
+
656
+ results = asyncio.run(solve_multiple())
657
+ ```
658
+ This completes in roughly the time of the slowest single captcha, not the sum of all of them.
659
+
660
+ ### Error handling
661
+
662
+ ```python
663
+ from captcha_solver_api import CaptchaClient, ApiError, CaptchaTimeoutError, NetworkError, ValidationError
664
+ client = CaptchaClient("your_api_key")
665
+ try:
666
+ result = client.solve(task)
667
+ except ValidationError as e:
668
+ print(f"Invalid argument: {e}")
669
+ except ApiError as e:
670
+ print(f"API error: {e.error_code} {e.error_description}")
671
+ except CaptchaTimeoutError:
672
+ print("Task timed out")
673
+ except NetworkError as e:
674
+ print(f"Network error: {e}")
675
+ ```
676
+
677
+ `TimeoutError` is still exported as a deprecated alias of `CaptchaTimeoutError`.
678
+ Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
679
+
680
+ ## Running the examples
681
+
682
+ See the dedicated [examples documentation](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/README.md) for the full
683
+ sync/async example list, setup steps, expected results, and placeholder guidance.
684
+
685
+ - **Image/click captchas** (`image_to_text.py`, `coordinates.py`,
686
+ `yandex_smartcaptcha_image.py`) run end-to-end with nothing but a valid
687
+ `CAPTCHA_API_KEY` -- they read sample images bundled in
688
+ [examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
689
+ - **Token captchas** (`recaptcha_v2.py`, `recaptcha_v2_enterprise.py`, `recaptcha_v3.py`,
690
+ `turnstile.py`, `yandex_smartcaptcha.py`, `geetest_v4.py`, `tencent.py`) use
691
+ placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
692
+ `YOUR_CAPTCHA_ID`) -- replace these with the real values from your own target
693
+ page before running.
694
+ - **`geetest_v3.py`** additionally needs `challenge` fetched fresh for every
695
+ request -- it's single-use and expires within seconds, so it can't be
696
+ hardcoded into a static example. `"https://target-site.com/path/to/geetest/init"`
697
+ is a placeholder; replace it with a request to your own target's equivalent
698
+ endpoint (or wherever it exposes `gt`/`challenge`) -- see the script for where
699
+ that fetch belongs in the flow.
700
+ - **Proxy variants** (`*Task` classes, as opposed to `*TaskProxyless`) use
701
+ placeholder proxy credentials (`1.2.3.4` / `user` / `password`) in every example
702
+ file -- proxies are a paid, account-specific resource, so there's nothing public
703
+ to ship here. Swap in your own proxy details to run those blocks for real.
704
+
705
+ ```bash
706
+ export CAPTCHA_API_KEY=your_api_key
707
+ python examples/sync/balance.py
708
+ python examples/sync/image_to_text.py
709
+ python examples/sync/coordinates.py
710
+ ```
711
+
712
+ **Verified against the live API** during development, using real target pages and
713
+ real proxy credentials in place of the placeholders shown above: every captcha
714
+ type in this SDK -- proxyless and with proxy -- returned a real, correctly-shaped
715
+ solution when pointed at a genuine target. `geetest_v3.py`'s request shape was
716
+ likewise confirmed correct when given a real, freshly-fetched `gt`/`challenge`
717
+ pair.
718
+
719
+ ## Requirements
720
+
721
+ - Python 3.9 or newer.
722
+ - Captcha Solver account with a valid API key.
723
+
724
+ ## API Documentation
725
+
726
+ Full API reference: https://captcha-solver.com/en/docs/captcha-types
727
+
728
+ ## License
729
+
730
+ This project is licensed under the MIT License. See [LICENSE.md](https://github.com/captcha-solver-api/python-sdk/blob/main/LICENSE.md) for details.