Skip to content

Node.js SDK

Verified v2.0.0· 2026-05-28

适用于 Node.js 和 TypeScript 的官方 CaptchaSonic 库 —— 现代化、基于 Promise、支持多种传输方式(gRPC / ConnectRPC / HTTP)。

CaptchaSonic Node.js SDK(captchasonic)是一个现代化、基于 Promise、TypeScript 优先的库,用于大规模求解 CAPTCHA。每个方法都返回 Promise,自带完整的类型定义,并可在三种可互换的传输方式上运行 —— 原生 gRPC(最快,仅限 Node.js)、ConnectRPC(可在 Node.js 和浏览器中运行)以及普通的 HTTP/JSON。瞬时错误会以指数退避方式自动重试。

可在 Node.js ≥ 18 和现代浏览器中运行,并兼容 Express、Fastify、Next.js、React、Vue 和 Vite。


安装

npm install captchasonic
# 或者
yarn add captchasonic
# 或者
pnpm add captchasonic

环境要求

要求说明
Node.js≥ 18.0.0(grpc 传输方式所必需)
模块格式ES Module —— 该包发布时带有 "type": "module"
浏览器任何支持 fetch 的现代浏览器;请使用 connecthttp 传输方式

该包仅以 ESM 形式发布。在 ESM 项目中(package.json 中包含 "type": "module",或使用 .mjs 文件)直接导入:

import { CaptchaSonic } from "captchasonic";

在 CommonJS 文件中,使用动态 import() 加载:

// CommonJS (.cjs / "type": "commonjs")
const { CaptchaSonic } = await import("captchasonic");

TIP

如果使用 TypeScript,请在 tsconfig.json 中设置 "module": "NodeNext"(或 "ESNext")和 "moduleResolution": "NodeNext",以便正确解析自带的类型定义。


身份验证

CaptchaSonic 控制台 创建 API 密钥,并将其作为构造函数的第一个参数传入:

import { CaptchaSonic } from "captchasonic";

const solver = new CaptchaSonic("YOUR_API_KEY");

切勿将密钥硬编码到版本控制中。请改为从环境变量读取密钥:

import { CaptchaSonic } from "captchasonic";

const solver = new CaptchaSonic(process.env.CAPTCHASONIC_API_KEY);

快速开始

每种验证码类型都有专门的 solve* 辅助方法,用于提交任务并返回结果。对于图像类任务,无需单独的轮询步骤 —— SDK 会自动处理。

import { CaptchaSonic } from "captchasonic";

const solver = new CaptchaSonic(process.env.CAPTCHASONIC_API_KEY);

const result = await solver.solveRecaptchaV2({
  images: tiles,            // Uint8Array[] | Buffer[] | file-path[]
  question: "traffic lights",
});

// 网格选择以图块索引的形式返回
console.log(result.typedSolution?.grid?.objects); // 例如 [2, 4, 7]

返回值: 图像方法返回的结果中,答案位于 typedSolution 下(此处为 typedSolution.grid.objects,即选中的图块索引);令牌方法在 solution 映射中返回令牌。

TIP

基于令牌的方法(Turnstile、Cloudflare、reCAPTCHA v2/v3 令牌、popular-captcha 令牌)会提交一个浏览器自动化任务并在内部轮询,直到令牌就绪 —— 默认最长 120 秒。


支持的验证码类型

所有图像方法都接受单个类型化的选项对象。图像可以是 Uint8Array、Node Buffer 或字符串文件路径(文件路径仅限 Node.js)。

reCAPTCHA v2(图像)

await solver.solveRecaptchaV2({
  images: tiles,                 // 3×3 网格通常为 9 个图块
  question: "traffic lights",    // 纯文本,或 Google 类别代码,如 "/m/015qff"
});
// → result.typedSolution.grid.objects  (number[] —— 选中的图块索引)

PopularCaptcha(hCaptcha 风格图像)

await solver.solvePopularCaptcha({
  images: tiles,                 // 1–64 个图块
  question: "Click each image with a cat",
  questionType: "objectClassify", // "objectClassify" | "grid" | "objectClick" | "objectDrag"
  examples,                      // objectClick 的可选参考图像
  websiteURL: "https://example.com",
});
// objectClassify/grid → typedSolution.grid.objects
// objectClick        → typedSolution.click
// objectDrag         → typedSolution.drag

GeeTest

// 九宫格(需要 question 和 images)
await solver.solveGeetest({ type: "nine", question: "Select all bicycles", images: tiles });

// click / icon(需要 question 和 images)
await solver.solveGeetest({ type: "click", question: "the bear", images: tiles });

// 滑块拼图(拼块 + 背景)
await solver.solveGeetest({ type: "slide", images: [piece], examples: [background] });

// 交换拼图
await solver.solveGeetest({ type: "match" });
await solver.solveGeetest({ type: "winlinze" });

返回值:grid/click 类型位于 typedSolution.grid.objects(或 typedSolution.click);slide 返回 typedSolution.slide.x

可接受的 type 别名:

标准名称别名
九宫格"nine""geetest_nine""9"
click / icon"click""geetest_click""icon"
slide"slide""geetest_slide"
match"match""geetest_match"
winlinze"winlinze""geetest_winlinze"

OCR / 图像转文本

await solver.solveOcr({ images: [img] });                                  // 通用 OCR
await solver.solveOcr({ images: [img], module: "mtcaptcha", maxLength: 4 });
await solver.solveOcr({ images: imgs, module: "bls", numeric: true, maxLength: 3 });
// → result.typedSolution.text.texts[0]
选项类型说明
module"common" | "mtcaptcha" | "bls" | "morocco"默认 "common"
numericboolean仅数字("bls" 时自动启用)
caseSensitiveboolean保留字母大小写
minLength / maxLengthnumber长度范围

TikTok

await solver.solveTikTok({ type: "click", question: "Select the shape", images });
await solver.solveTikTok({ type: "whirl", question: "Rotate to match", images, examples }); // 需要 examples
await solver.solveTikTok({ type: "slide", question: "Slide to fit", images, examples });    // 需要 examples

返回值:click 位于 typedSolution.clickwhirl/slide 返回 typedSolution.slide.x

type 接受 "click"/"tiktok_click""whirl"/"tiktok_whirl""slide"/"tiktok_slide"

Binance

await solver.solveBinance({ type: "grid", question: "Select the bicycle", images });
await solver.solveBinance({ type: "slide", images: [puzzle], examples: [background] });

返回值:grid 位于 typedSolution.grid.objectsslide 返回 typedSolution.slide.x

type 接受 "grid"/"binance_grid""slide"/"binance_slide"

AWS WAF

solveAwsWaf 使用位置参数。question 的格式为 "type:category:target"

await solver.solveAwsWaf(tiles, "grid:vehicles:cars");

返回值:选中的图块索引位于 typedSolution.grid.objects

滑块图像(本地,无 AI)

使用轮廓检测在本地确定滑块偏移量。接受一张合并图像,或 [background, piece]

const r = await solver.solveSlideImage({ images: ["slide_bg.png", "piece.png"] });
console.log(r.typedSolution?.slide?.x); // 像素偏移量,例如 142

返回值:滑块偏移量(像素)位于 typedSolution.slide.x

令牌方法(浏览器自动化)

这些方法会提交任务并在内部轮询,直到返回令牌(最长至轮询超时时间,默认 120 秒)。

await solver.solveTurnstile({ websiteURL, websiteKey, proxy });          // proxy 可选
await solver.solveRecaptchaV2Token({ websiteURL, websiteKey, proxy });   // proxy 可选
await solver.solveRecaptchaV3Token({ websiteURL, websiteKey, proxy });   // proxy 可选
await solver.solvePopularCaptchaToken({ websiteURL, websiteKey, proxy, metadata }); // proxy 可选
await solver.solveCloudflare({ websiteURL, websiteKey, proxy });         // proxy 必填

返回值:令牌位于响应的 solution 映射中(例如 result.solution.tokenresult.solution.gRecaptchaResponse,取决于验证码类型)。


TypeScript 用法

SDK 为每个选项对象和响应导出类型。请使用 import type 导入它们。

import { CaptchaSonic } from "captchasonic";
import type { SolveGeetestOptions, GetTaskResultResponse } from "captchasonic";

const solver = new CaptchaSonic(process.env.CAPTCHASONIC_API_KEY!);

const opts: SolveGeetestOptions = {
  type: "nine",
  question: "Select all bicycles",
  images: tiles,
};

const result = await solver.solveGeetest(opts);
console.log(result.typedSolution?.grid?.objects);

导出的类型

import type {
  CaptchaSonicOptions,
  ImageInput,
  SolvePopularCaptchaOptions,
  SolveRecaptchaV2Options,
  SolveGeetestOptions,
  SolveOcrOptions,
  SolveTikTokOptions,
  SolveBinanceOptions,
  SolveTurnstileOptions,
  SolvePopularCaptchaTokenOptions,
  SolveRecaptchaV2TokenOptions,
  SolveRecaptchaV3TokenOptions,
  SolveCloudflareOptions,
  SolveSlideImageOptions,
  GeetestSubtype,
  TikTokSubtype,
  BinanceSubtype,
  Task,
  CreateTaskResponse,
  GetTaskResultResponse,
} from "captchasonic";

ImageInputUint8Array | Buffer | string


代理支持

令牌 / 浏览器自动化方法接受可选的 proxy 字符串,格式为 http://user:pass@host:port

await solver.solveTurnstile({
  websiteURL: "https://example.com",
  websiteKey: "0x4AAAAAAA...",
  proxy: "http://user:[email protected]:8080",
});

WARNING

solveCloudflare 始终需要代理 —— 该方法的 proxy 字段为必填项。其他令牌方法在省略 proxy 时以无代理方式运行。

对于企业版 hCaptcha,你还可以向 solvePopularCaptchaToken 传递 metadatarqdatarqtokenfingerprint)。


配置

将选项对象作为构造函数的第二个参数传入。仅支持以下选项。

const solver = new CaptchaSonic("YOUR_API_KEY", {
  transport: "connect",   // "grpc"(默认) | "connect" | "http"
  timeout: 180_000,       // 最大轮询等待时间(毫秒,别名:timeoutMs);单次调用默认 30000
  pollingInterval: 5_000, // 轮询频率(毫秒,默认 2000)
  baseUrl: "https://api.captchasonic.com", // 覆盖端点(别名:url)
});
选项类型默认值说明
transport"grpc" | "connect" | "http""grpc"传输协议(见下表)
timeout / timeoutMsnumber单次调用 30000请求超时;timeout 同时限制轮询等待时间
pollingIntervalnumber2000令牌任务的轮询频率
url / baseUrlstring因传输方式而异覆盖 API 端点

传输方式

传输方式运行环境协议
grpc仅 Node.js基于 HTTP/2 的 gRPC 二进制 —— 延迟最低,以原始二进制发送图像
connectNode.js 和浏览器基于 fetch 的 ConnectRPC
httpNode.js 和浏览器基于 fetch 的普通 REST/JSON

TIP

在浏览器中请使用 connect(推荐)或 http。原生 gRPC 需要 Node.js。使用 connect/http 时,图像在发送前会自动编码为 base64;使用 grpc 时,图像以原始二进制发送,无额外开销。


错误处理

所有 API 级别的失败都会抛出 SonicError,它继承自内置的 Error。它带有数字 errorId,并将 name 设置为相应的错误名称。

import { CaptchaSonic, SonicError } from "captchasonic";

try {
  const result = await solver.solveGeetest({ type: "nine", question: "bicycles", images });
} catch (err) {
  if (err instanceof SonicError) {
    console.error(err.errorId); // 1–6
    console.error(err.name);    // 例如 "InvalidApiKeyError"
    console.error(err.message);
  } else {
    throw err; // 网络 / 意外错误
  }
}
errorIdname原因处理方式
1InvalidApiKeyErrorAPI 密钥缺失或无效检查控制台中的密钥
2InsufficientBalanceError额度不足充值余额
3DailyLimitExceededError超出每日配额等待每日重置或提升套餐
4MinuteLimitExceededError触发每分钟速率限制退避后稍后重试
5QuotaExceededError套餐配额耗尽升级套餐
6PlanExpiredError订阅已过期续订订阅

TIP

瞬时 gRPC 错误会以指数退避方式自动重试(最多 3 次),因此通常只需处理上面列出的 SonicError 情况。


账户辅助方法

const balance = await solver.getBalance(); // → number (USD)

const health = await solver.healthCheck(); // → { healthy: boolean, version: string }

如果需要直接控制任务提交和轮询,可使用底层任务方法:

const created = await solver.createTask(task);        // 提交 Partial<Task>
const result  = await solver.getTaskResult(taskId);   // 轮询结果

故障排查

require is not defined / Cannot use import statement outside a module —— 该包仅为 ESM。请在 ESM 项目中使用 import,或在 CommonJS 中使用 await import("captchasonic")。参见安装

grpc 传输方式在浏览器中失败 —— 原生 gRPC 仅限 Node.js。请切换到 transport: "connect"transport: "http"

每次调用都返回 InvalidApiKeyError —— 确认密钥作为构造函数的第一个参数传入,且没有意外为 undefined(例如环境变量缺失)。

令牌方法超时 —— 令牌任务最长轮询 timeout 毫秒(默认 120000)。请增大 timeout,并核实 websiteURL / websiteKey 与目标页面匹配。对于 Cloudflare,需提供有效的 proxy

文件路径图像无法加载 —— 文件路径以同步方式读取,仅限 Node.js;在浏览器中请改为传入 Uint8Array


资源