CaptchaAI Node.js & TypeScript SDK β an official CAPTCHA solver and solving API client for reCAPTCHA v2/v3/Enterprise, Cloudflare Turnstile, Cloudflare Challenge, GeeTest v3, and image CAPTCHAs.
Call one method per captcha type; the SDK handles HTTP, polling, retries, and typed error mapping with zero external runtime dependencies.
For full copy-paste examples of every captcha type and feature, see EXAMPLES.md.
- Examples
- Installation
- Requirements
- Quick start
- Configuration
- Solve result
- Normal captcha
- Grid captcha
- BLS captcha
- reCAPTCHA v2
- reCAPTCHA v3
- Cloudflare Turnstile
- Cloudflare Challenge
- GeeTest v3
- CaptchaFox (beta)
- Friendly Captcha (beta)
- Lemin (beta)
- Other methods
- Error handling
- AsyncCaptchaAI
- Proxies
- License
npm install captchaai-javascriptNode.js >= 18 (uses native fetch and AbortSignal.timeout). Zero external runtime dependencies.
import { CaptchaAI } from "captchaai-javascript";
const solver = new CaptchaAI({ apiKey: "YOUR_32_CHAR_API_KEY" });
const result = await solver.recaptchaV2(
"YOUR_SITEKEY",
"https://example.com"
);
console.log(result.solution);
await solver.close();Create a client with your API key from CaptchaAI. The constructor validates the key and starts a background threadsInfo call to read your account thread cap.
import { CaptchaAI } from "captchaai-javascript";
const solver = new CaptchaAI({
apiKey: "YOUR_32_CHAR_API_KEY",
proxy: "user:pass@host:port", // optional
proxyType: "HTTP", // required when proxy is set
autoRetry: true,
baseUrl: "https://ocr.captchaai.com",
threadBusyTimeoutSeconds: 120,
maxRetries: 5, // optional; overrides autoRetry when set
networkTimeoutSeconds: 30,
maxPollSeconds: 180,
jitterMaxSeconds: 1,
submitBackoffBaseSeconds: 5,
});| Option | Default | Description |
|---|---|---|
apiKey |
(required) | 32-character CaptchaAI API key |
proxy |
undefined |
"user:pass@host:port" applied to every solve |
proxyType |
undefined |
HTTP / HTTPS / SOCKS4 / SOCKS5 β required when proxy is set |
autoRetry |
true |
true = SDK retries transient errors with backoff; false = raise immediately |
baseUrl |
https://ocr.captchaai.com |
API host for in.php / res.php |
threadBusyTimeoutSeconds |
120 |
Seconds to keep retrying while all account threads are busy |
maxRetries |
5 (implicit) |
When explicitly set: 0 disables retries; N > 0 enables up to N submit attempts (supersedes autoRetry) |
networkTimeoutSeconds |
30 |
Per-request HTTP timeout |
maxPollSeconds |
180 |
Poll deadline before TimeoutError |
jitterMaxSeconds |
1 |
Random jitter added to wait intervals |
submitBackoffBaseSeconds |
5 |
Base interval for exponential submit backoff |
A bad key raises InvalidKeyError before any solve runs. Call solver.close() when finished.
Every solve method returns a SolveResult:
result.taskId // string β task ID from submit (always present)
result.solution // string | string[] | Record<string, unknown> β token, cell indices, or structured answer
result.userAgent // string | undefined β set for Enterprise / Cloudflare Challenge / CaptchaFox
result.raw // Record<string, unknown> | undefined β full API response (debugging)
result.rawText // string | undefined β unparsed solution string before JSON parsing
result.toString() // token string for common token typesReuse result.userAgent on the target site when it is present (Enterprise reCAPTCHA, Cloudflare Challenge, CaptchaFox).
Solve a text/image captcha. image may be a file path, URL, data-URI, raw base64, or Uint8Array.
import { CaptchaAI } from "captchaai-javascript";
const solver = new CaptchaAI({ apiKey: "YOUR_32_CHAR_API_KEY" });
const result = await solver.normal("captcha.png", {
numeric: 1, // 0=any, 1=digits, 2=letters, 3=digits+letters, 4=no digits
minLen: 4,
maxLen: 6,
phrase: 0, // 0=single word, 1=multi-word
caseSensitive: 0, // 0=insensitive, 1=case-sensitive
lang: "en",
instructions: "Type the characters you see",
});
console.log(result.solution);
await solver.close();Solve a tile-selection captcha. gridSize must be "3x3" or "4x4". solution is a list of cell indices.
const result = await solver.grid(
"grid.png",
"select all traffic lights",
{ gridSize: "3x3" }
);
console.log(result.solution);Solve a BLS multi-image captcha. Pass exactly 9 images (path, URL, base64, or Uint8Array each). solution is a list of cell indices.
const images = Array.from({ length: 9 }, (_, i) => `img${i}.png`);
const result = await solver.bls(images, "YOUR_INSTRUCTIONS");
console.log(result.solution);Solve reCAPTCHA v2 (standard, invisible, or enterprise).
// Standard
const result = await solver.recaptchaV2(
"YOUR_SITEKEY",
"https://example.com"
);
console.log(result.solution);
// Invisible
const invisibleResult = await solver.recaptchaV2(
"YOUR_SITEKEY",
"https://example.com",
{ invisible: true }
);
// Enterprise
const enterpriseResult = await solver.recaptchaV2(
"YOUR_SITEKEY",
"https://example.com",
{ enterprise: true, action: "login" }
);
console.log(enterpriseResult.solution);
console.log(enterpriseResult.userAgent);Solve reCAPTCHA v3. minScore defaults to 0.3.
// Standard
const result = await solver.recaptchaV3(
"YOUR_SITEKEY",
"https://example.com",
"verify",
0.7
);
console.log(result.solution);
// Enterprise
const entResult = await solver.recaptchaV3(
"YOUR_SITEKEY",
"https://example.com",
"login",
0.9,
{ enterprise: true }
);Solve Cloudflare Turnstile.
const result = await solver.turnstile(
"0x4AAAAAAAB...",
"https://example.com",
{ action: "login" }
);
console.log(result.solution);Solve Cloudflare Challenge (5s / Managed / Non-Interactive). A working proxy is mandatory.
const result = await solver.cloudflareChallenge(
"https://example.com",
"<html>...</html>", // full page HTML
"user:pass@host:port", // required
"HTTP", // required
"Mozilla/5.0 ..." // must match the session that fetched the HTML
);
console.log(result.solution); // clearance tokenSolve GeeTest v3. Requires gt, challenge, and url.
const result = await solver.geetestV3(
"YOUR_GT",
"YOUR_CHALLENGE",
"https://example.com"
);
console.log(result.solution);
// { geetest_challenge, geetest_validate, geetest_seccode }Solve CaptchaFox. A working proxy is mandatory.
const result = await solver.captchafox(
"YOUR_SITEKEY",
"https://example.com",
"user:pass@host:port",
"HTTP"
);
console.log(result.solution);Solve Friendly Captcha (v1 or v2). No proxy is required.
const result = await solver.friendlyCaptcha(
"YOUR_SITEKEY",
"https://example.com",
{ version: "v1" }
);
console.log(result.solution);Solve Lemin puzzle.
const result = await solver.lemin(
"YOUR_CAPTCHA_ID",
"lemin-cropped-captcha",
"https://example.com"
);
console.log(result.solution);
// { answer, challenge_uuid }CaptchaAI is thread-based. Check current usage:
const info = await solver.threadsInfo();
// { threads: 10, working_threads: 3 }Submit now and poll later:
const taskId = await solver.send("recaptcha_v2", {
googlekey: "YOUR_SITEKEY",
pageurl: "https://example.com",
});
const result = await solver.getResult("recaptcha_v2", taskId);
console.log(result.solution);await solver.close();All SDK errors inherit from CaptchaAIError:
import {
CaptchaAI,
CaptchaAIError,
InvalidKeyError,
ValidationError,
ProxyError,
ThreadLimitError,
NoThreadsError,
UnsolvableError,
APIError,
NetworkError,
TimeoutError,
} from "captchaai-javascript";
const solver = new CaptchaAI({ apiKey: "YOUR_32_CHAR_API_KEY" });
try {
const result = await solver.recaptchaV2(
"YOUR_SITEKEY",
"https://example.com"
);
console.log(result.solution);
} catch (error) {
if (error instanceof InvalidKeyError) {
// wrong-length key, or API rejected the key
} else if (error instanceof ValidationError) {
// missing/invalid params, bad image input, missing required proxy, etc.
} else if (error instanceof ProxyError) {
// bad proxy or proxy connection failed
} else if (error instanceof ThreadLimitError) {
// all account threads busy
} else if (error instanceof NoThreadsError) {
// account expired or has no active plan
} else if (error instanceof UnsolvableError) {
// service could not solve the captcha
} else if (error instanceof NetworkError) {
// could not reach the API
} else if (error instanceof TimeoutError) {
// poll deadline exceeded before a result was ready
} else if (error instanceof APIError) {
// unexpected / malformed API response
} else if (error instanceof CaptchaAIError) {
// any other SDK error
}
}Proxies are supported at client level and per call. Format: "user:pass@host:port". proxyType is required whenever a proxy is set (HTTP, HTTPS, SOCKS4, or SOCKS5).
// Client-level (every solve)
const solver = new CaptchaAI({
apiKey: "YOUR_32_CHAR_API_KEY",
proxy: "user:pass@host:port",
proxyType: "HTTP",
});
// Per-call override (does not mutate client config)
const result = await solver.recaptchaV2(
"YOUR_SITEKEY",
"https://example.com",
{
proxy: "user:pass@other-host:port",
proxyType: "SOCKS5",
}
);- π Official Website
- π API Documentation
- π¦ npm Package
- π§© Chrome Extension
This project is licensed under the MIT License.
Copyright (c) 2026 Dev@Captchaai