# Node.js

> YesCaptcha 的 Node.js 示例（Node.js 18+，用自带的 fetch，不需要第三方库）：查询余额、识别图片验证码、可复用的客户端类（创建任务、每 5 秒轮询）。

Source: https://docs.yescaptcha.com/zh/samples/nodejs/ · Last verified: 2026-10-15

运行环境：Node.js 18 以上（自带 `fetch`），示例是 ES module（`.mjs`），不需要安装第三方库。运行前设置环境变量：

```bash
export YESCAPTCHA_CLIENT_KEY=你的clientKey
```

## 查询余额

不扣点，用来确认 clientKey 正确：

get-balance.mjs

```js
// Check the balance. getBalance is free and is a quick way to verify your clientKey. Node.js 18+
const CLIENT_KEY = process.env.YESCAPTCHA_CLIENT_KEY;

const res = await fetch('https://api.yescaptcha.com/getBalance', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ clientKey: CLIENT_KEY }),
});
const data = await res.json();
if (data.errorId) {
  // e.g. ERROR_KEY_DOES_NOT_EXIST when the clientKey is wrong
  console.log('error:', data.errorCode, data.errorDescription);
} else {
  console.log('balance (points):', data.balance);
}
```

## 识别一张图片验证码

同步类型 `ImageToTextTaskOcrBase`，一次请求拿到结果。示例图片：[captcha.jpg](https://docs.yescaptcha.com/samples/captcha.jpg)。运行 `node quickstart.mjs captcha.jpg`。

quickstart.mjs

```js
// First request: read an alphanumeric image captcha with ImageToTextTaskOcrBase (synchronous, 2 points per image).
// Usage: YESCAPTCHA_CLIENT_KEY=your_client_key node quickstart.mjs captcha.png
import { readFileSync } from 'node:fs';

const CLIENT_KEY = process.env.YESCAPTCHA_CLIENT_KEY;
const body = readFileSync(process.argv[2] ?? 'captcha.png').toString('base64'); // no "data:" prefix

const res = await fetch('https://api.yescaptcha.com/createTask', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ clientKey: CLIENT_KEY, task: { type: 'ImageToTextTaskOcrBase', body } }),
});
const data = await res.json();
if (data.errorId) throw new Error(`${data.errorCode}: ${data.errorDescription}`);
console.log('text:', data.solution.text);
```

## 可复用的客户端

yescaptcha.mjs

```js
// A small client you can copy into your project: create tasks, poll results, check the balance. Node.js 18+
//
//   import { YesCaptcha } from './yescaptcha.mjs';
//   const client = new YesCaptcha(process.env.YESCAPTCHA_CLIENT_KEY);
//   const solution = await client.solve({ type: 'NoCaptchaTaskProxyless', websiteURL: '...', websiteKey: '...' });

export class YesCaptchaError extends Error {
  constructor(code, description) {
    super(`${code}: ${description}`);
    this.code = code;
  }
}

export class YesCaptcha {
  constructor(clientKey, { endpoint = 'https://api.yescaptcha.com', pollInterval = 5000, timeout = 180000 } = {}) {
    this.clientKey = clientKey;
    this.endpoint = endpoint.replace(/\/$/, '');
    this.pollInterval = pollInterval; // 5 s: polling the same taskId more often only returns "processing"
    this.timeout = timeout;
  }

  async call(method, payload = {}) {
    const res = await fetch(`${this.endpoint}/${method}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ clientKey: this.clientKey, ...payload }),
    });
    const data = await res.json();
    if (data.errorId) throw new YesCaptchaError(data.errorCode, data.errorDescription);
    return data;
  }

  async balance() {
    return (await this.call('getBalance')).balance;
  }

  async solve(task) {
    const created = await this.call('createTask', { task });
    if (created.status === 'ready') return created.solution; // synchronous types return the solution directly
    const deadline = Date.now() + this.timeout;
    while (Date.now() < deadline) {
      await new Promise((r) => setTimeout(r, this.pollInterval));
      const result = await this.call('getTaskResult', { taskId: created.taskId });
      if (result.status === 'ready') return result.solution;
    }
    throw new Error(`task ${created.taskId} not ready after ${this.timeout} ms`);
  }
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const client = new YesCaptcha(process.env.YESCAPTCHA_CLIENT_KEY);
  console.log('balance:', await client.balance());
}
```

```js
import { YesCaptcha } from './yescaptcha.mjs';

const client = new YesCaptcha(process.env.YESCAPTCHA_CLIENT_KEY);
const solution = await client.solve({
  type: 'TurnstileTaskProxyless',
  websiteURL: 'https://example.com/login',
  websiteKey: '0x4AAAAAAA_SITE_KEY',
});
console.log(solution.token);
```

出错时抛出 `YesCaptchaError`，`err.code` 是错误码，含义见 [错误码](https://docs.yescaptcha.com/zh/api/errors/)。
