Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
fail-fast: false
matrix:
# Matches engines.node: ">=18" in package.json
node-version: [18, 20, 22]
node-version: [18, 20, 22, 24]

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -51,11 +51,10 @@ jobs:

integration:
name: Integration (real API)
# Only on schedule and manual dispatch. Deliberately not run on
# pull_request: the tests spend real account balance, and secrets are
# unavailable in PRs from forks anyway -- the tests would silently skip
# and produce a false-green result.
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
# Run for same-repository pull requests as well as scheduled and manual
# checks. GitHub does not expose repository secrets to pull requests from
# forks, so those runs fail at the explicit secret check below instead of
# producing a false-green result.
runs-on: ubuntu-latest

steps:
Expand Down
193 changes: 124 additions & 69 deletions README.md

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Security Policy

## Supported versions

Security fixes are provided for the latest `1.x` release of the SDK.

| Version | Supported |
|---|---|
| 1.x | Yes |
| < 1.0 | No |

## Reporting a vulnerability

Please do not report security vulnerabilities in public GitHub issues.

Use GitHub's private vulnerability reporting instead:

1. Open the repository's **Security** tab.
2. Select **Advisories**.
3. Select **Report a vulnerability**.

Include the affected SDK version, a clear description of the issue, steps to
reproduce it, and its potential impact. If possible, include a minimal proof of
concept and any suggested mitigation.

We will acknowledge the report, investigate it, and coordinate disclosure with
the reporter. Please allow time for a fix to be prepared and released before
publishing details.
207 changes: 35 additions & 172 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,192 +1,55 @@
# Examples

Runnable scripts for every captcha type the SDK supports. Each file is standalone: it builds a
`CaptchaClient`, creates one or two tasks, waits for the solution and prints it. Nothing here is
imported by the library itself — the directory exists to be read and executed.

The same 11 scenarios are provided twice, once per calling style:

| Suite | Style | Look here if |
|---|---|---|
| [async/](async) | `async/await` | your code is `await`-based (the common case) |
| [sync/](sync) | `.then()/.catch()` | you chain promises instead of awaiting them |

Both suites call the same `CaptchaClient`. The SDK exposes a single promise-based API, and the split
only demonstrates two ways of consuming it — JavaScript has no blocking HTTP client, so there is no
true synchronous variant the way the Python SDK has `requests` vs. `httpx`.

## Table of contents

- [Setup](#setup)
- [Running an example](#running-an-example)
- [Example index](#example-index)
- [What each example covers](#what-each-example-covers)
- [Before you run](#before-you-run)
Every file is a standalone Promise-chain example and contains exactly one API
operation. Examples with a customer proxy use the `_proxy.js` suffix.

## Setup

**1. Install dependencies.** The scripts use `dotenv`, which is a devDependency of the repo:
Install dependencies and provide your API key:

```bash
npm install
```

**2. Provide an API key.** Copy the template and fill in your key:

```bash
cp .env.example .env
```

```
```text
CAPTCHA_API_KEY=your_api_key_here
```

Every script starts with `import 'dotenv/config'` and reads `process.env.CAPTCHA_API_KEY`, falling
back to the literal `'YOUR_API_KEY'` when the variable is missing. That fallback keeps the script
importable, but the API will reject it — set a real key before expecting results.

**3. Node.js 18 or newer.** The examples rely on global `fetch` and, in `async/`, on top-level
`await`.

> The scripts import the SDK by package name, exactly as consumer applications do:
> `import { CaptchaClient, Tasks } from '@captcha-solver-api/javascript-sdk';`

## Running an example

Run from the repository root:
Run an example from the repository root:

```bash
node examples/async/balance.js
node examples/sync/recaptcha_v2.js
node examples/recaptcha_v2.js
```

`balance.js` is the one file that works as-is — it only needs a valid key. Every other example ships
with placeholder values (`https://example.com/login`, `6Le-xxxxxxxxx`, …) that you must replace with
values from your own target page. See [Before you run](#before-you-run).

Most files contain **two independent blocks** — a proxyless one and a with-proxy one — that both run
on execution. Comment out the block you don't need, or the script will submit two tasks and spend
twice the balance.
Replace placeholder URLs, site keys, application IDs, dynamic values, and
proxy credentials before running token CAPTCHA examples.

## Example index

| Captcha type | async | sync | Task classes | Solution fields |
|---|---|---|---|---|
| reCAPTCHA v2 | [recaptcha_v2.js](async/recaptcha_v2.js) | [recaptcha_v2.js](sync/recaptcha_v2.js) | `RecaptchaV2Proxyless`, `RecaptchaV2` | `gRecaptchaResponse` |
| reCAPTCHA v2 Enterprise | [recaptcha_v2_enterprise.js](async/recaptcha_v2_enterprise.js) | [recaptcha_v2_enterprise.js](sync/recaptcha_v2_enterprise.js) | `RecaptchaV2EnterpriseProxyless`, `RecaptchaV2Enterprise` | `gRecaptchaResponse` |
| Cloudflare Turnstile | [turnstile.js](async/turnstile.js) | [turnstile.js](sync/turnstile.js) | `TurnstileProxyless`, `Turnstile` | `token` |
| GeeTest v3 | [geetest_v3.js](async/geetest_v3.js) | [geetest_v3.js](sync/geetest_v3.js) | `GeeTestProxyless`, `GeeTest` | `challenge`, `validate`, `seccode` |
| GeeTest v4 | [geetest_v4.js](async/geetest_v4.js) | [geetest_v4.js](sync/geetest_v4.js) | `GeeTestProxyless`, `GeeTest` | `captcha_id`, `lot_number`, `pass_token`, `gen_time`, `captcha_output` |
| Yandex SmartCaptcha | [yandex_smartcaptcha.js](async/yandex_smartcaptcha.js) | [yandex_smartcaptcha.js](sync/yandex_smartcaptcha.js) | `YandexSmartCaptchaTaskProxyless`, `YandexSmartCaptchaTask` | `token` |
| Yandex SmartCaptcha Image | [yandex_smartcaptcha_image.js](async/yandex_smartcaptcha_image.js) | [yandex_smartcaptcha_image.js](sync/yandex_smartcaptcha_image.js) | `YandexSmartCaptchaImageTask` | `coordinates` |
| Tencent | [tencent.js](async/tencent.js) | [tencent.js](sync/tencent.js) | `TencentTaskProxyless`, `TencentTask` | `appid`, `ret`, `ticket`, `randstr` |
| Image to Text | [image_to_text.js](async/image_to_text.js) | [image_to_text.js](sync/image_to_text.js) | `ImageToText` | `text` |
| Coordinates (click) | [coordinates.js](async/coordinates.js) | [coordinates.js](sync/coordinates.js) | `CoordinatesTask` | `coordinates` |
| Account balance | [balance.js](async/balance.js) | [balance.js](sync/balance.js) | — (`getBalance()`) | number |

## What each example covers

### reCAPTCHA v2

The baseline example, and the best one to read first. Shows the two shapes every proxy-capable type
follows: `RecaptchaV2Proxyless` (the service uses its own IPs) and `RecaptchaV2` with the five proxy
fields — `proxyType`, `proxyAddress`, `proxyPort`, `proxyLogin`, `proxyPassword`. Also documents the
two optional client settings, `timeout` and `pollingInterval`, and the `isInvisible` flag for
invisible widgets.

### reCAPTCHA v2 Enterprise

Same two shapes as v2, with `enterprisePayload` added. If the target site passes extra parameters to
`grecaptcha.enterprise.render()`, they must be forwarded in that object — otherwise the returned
token is rejected by the site even though the API call succeeded.


### Cloudflare Turnstile

Proxyless and with-proxy variants. The important detail is in the comments: there's no `userAgent`
input for this type -- the worker picks its own while solving and returns it as `result.userAgent`
instead, and the token is tied to that fingerprint, so you must submit it with that exact User-Agent.
For Cloudflare Challenge pages, `action`, `data` (the `data-cdata` attribute) and `pagedata` (the
`chlPageData` parameter -- lowercase, unlike every other field here) also have to be extracted from
the page and passed along.

### GeeTest v3

The only example that performs a **request of its own before solving**. The `challenge` value is
session-specific and must be fresh for every task, so the script fetches one first and then builds
the task. The fetch URL is a deliberate placeholder — see [Before you run](#before-you-run). Uses
`timeout: 300000` and `pollingInterval: 10000`, since GeeTest is among the slowest types. `version`
is omitted because v3 is the default.

### GeeTest v4

Same task classes as v3, different identification: v4 drops `gt`/`challenge` entirely and identifies
the widget by `captcha_id` inside `initParameters`, with `version: 4` set explicitly. Solution shape
differs from v3 as well — `captcha_output` and friends instead of `validate`/`seccode`.

### Yandex SmartCaptcha

Covers the **token** challenge, proxyless and with proxy. `websiteKey` is the sitekey from the page
a different task type — it lives in the coordinates example below.

### Tencent

Proxyless and with proxy. `appId` is read from the page source. `captchaScript` is only needed when
the site loads the widget from a non-default script URL.

### Image to Text

Three blocks, no proxy variant, all active. *Basic* submits the shipped letters-only sample
(`text-captcha.png`) with matching character-set hints. *Advanced* solves a different image entirely
— a real math captcha (`captcha-math.png`) with its own instruction image (`captcha-math-instructions.png`)
— using the rest of the hints that speed up recognition: `phrase`, `math`, `comment`,
`imgInstructions`. *With language pool* shows that `languagePool` is the **second argument to
`solve()`**, not a task field: `solve(task, 'en')` picks an English-speaking worker pool (`'en'` or
`'ru'`).

### Coordinates (click captcha)

Three blocks, no proxy variant, all active. *Basic* passes the shipped grid captcha
(`coordinates-captcha.png`) plus a `comment` telling the worker what to click — it repeats the
instruction printed on the image itself, since nothing guarantees the worker reads that. *Advanced*
solves a different image — real traffic-lights photo (`traffic-lights.png`) with its own instruction
image (`traffic-lights-instructions.png`) and `minClicks`/`maxClicks` limits. *Yandex SmartCaptcha
token challenge.

### Account balance

The shortest script: one `getBalance()` call returning the available amount as a number. It needs no
target page and no placeholder edits, which makes it the fastest way to confirm that your key and
network access work.

## Before you run

Every example except `balance.js` needs something replaced first.

| Example | What you must supply |
|---|---|
| `balance.js` | Nothing — runs as-is with a valid key |
| `turnstile.js` | Real `websiteURL` and `websiteKey`; for Challenge pages also `action`, `data`, `pagedata` |
| `yandex_smartcaptcha.js` | Real `websiteURL` and `websiteKey` |
| `tencent.js` | Real `websiteURL` and `appId` |
| `geetest_v3.js` | Real `websiteURL` and `gt`, **plus a real init endpoint** (see below) |
| `geetest_v4.js` | Real `websiteURL` and `captcha_id` |
| `image_to_text.js` | Nothing — all sample images ship in [assets/](assets/) |
| `coordinates.js` | Nothing — all sample images ship in [assets/](assets/) |

**Both image examples run entirely as-is**, with a valid key and nothing else — every block,
[assets/](assets/) and are read through `new URL('../assets/…', import.meta.url)`, which resolves
against the script rather than the working directory — so `node examples/async/coordinates.js` works
from the repository root just as well as from anywhere else. Point the read at your own file to solve
a different image.

**`geetest_v3.js` will not run end-to-end as-is.** It fetches
`https://target-site.com/path/to/geetest/init`, which is a placeholder, not a live endpoint; the
script exits with code 1 when that fetch fails. Point it at your real target page — or wherever it
exposes a fresh `challenge` — before running. The block is there to show *where* that fetch belongs
in the flow.

Proxy credentials (`1.2.3.4:8080`, `user`/`password`) are placeholders too. If you only want the
proxyless path, comment out the with-proxy block rather than leaving it to fail.

Full API reference: https://captcha-solver.com/en/docs/captcha-types
| CAPTCHA type | Without customer proxy | With customer proxy |
|---|---|---|
| reCAPTCHA v2 | [`recaptcha_v2.js`](recaptcha_v2.js) | [`recaptcha_v2_proxy.js`](recaptcha_v2_proxy.js) |
| reCAPTCHA v2 Enterprise | [`recaptcha_v2_enterprise.js`](recaptcha_v2_enterprise.js) | [`recaptcha_v2_enterprise_proxy.js`](recaptcha_v2_enterprise_proxy.js) |
| reCAPTCHA v3 | [`recaptcha_v3.js`](recaptcha_v3.js) | No separate proxy task |
| Cloudflare Turnstile | [`turnstile.js`](turnstile.js) | [`turnstile_proxy.js`](turnstile_proxy.js) |
| GeeTest v3 | [`geetest_v3.js`](geetest_v3.js) | [`geetest_v3_proxy.js`](geetest_v3_proxy.js) |
| GeeTest v4 | [`geetest_v4.js`](geetest_v4.js) | [`geetest_v4_proxy.js`](geetest_v4_proxy.js) |
| Yandex SmartCaptcha | [`yandex_smartcaptcha.js`](yandex_smartcaptcha.js) | [`yandex_smartcaptcha_proxy.js`](yandex_smartcaptcha_proxy.js) |
| Yandex SmartCaptcha Image | [`yandex_smartcaptcha_image.js`](yandex_smartcaptcha_image.js) | No separate proxy task |
| Tencent | [`tencent.js`](tencent.js) | [`tencent_proxy.js`](tencent_proxy.js) |
| Image to Text | [`image_to_text.js`](image_to_text.js) | No separate proxy task |
| Coordinates | [`coordinates.js`](coordinates.js) | No separate proxy task |
| Account balance | [`balance.js`](balance.js) | Not applicable |

Additional one-scenario examples:

- [`image_to_text_math.js`](image_to_text_math.js) — math CAPTCHA with an instruction image.
- [`image_to_text_language_pool.js`](image_to_text_language_pool.js) — select the English worker pool.
- [`coordinates_traffic_lights.js`](coordinates_traffic_lights.js) — click coordinates with an instruction image.

> **Important:** `geetest_v3.js` and `geetest_v3_proxy.js` contain a placeholder
> initialization endpoint. Replace it with the target website's endpoint and
> fetch a fresh `challenge` for every task.

> **Important:** Proxy examples contain placeholder proxy details. Replace all
> of them with your own proxy settings before running a script.
Loading
Loading