reCAPTCHA, hCaptcha & image captchas in Node.js — updated August 2026
TL;DR: No npm package needed — the API is plain JSON. Create a task with axios (or native fetch on Node 18+), poll every 3 seconds, inject the token. 50 free solves on signup, no credit card.
Token captchas are solved asynchronously: create the task, poll for the result. The same class handles reCAPTCHA v2, hCaptcha and AWS WAF — only the type and key fields change (see hCaptcha solver and AWS WAF solver for their payloads):
import axios from 'axios';
const API_KEY = process.env.CAPTCHAKINGS_KEY;
const API = 'https://api.captchakings.com';
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
export async function solveRecaptchaV2(websiteURL, websiteKey) {
// 1. Create the task
const { data: created } = await axios.post(`${API}/createTask`, {
clientKey: API_KEY,
task: {
type: 'RecaptchaV2TaskProxyless',
websiteURL,
websiteKey
}
});
if (!created.taskId) throw new Error('createTask failed: ' + JSON.stringify(created));
// 2. Poll until ready (timeout 120s)
const deadline = Date.now() + 120_000;
while (Date.now() < deadline) {
await sleep(3000);
const { data: result } = await axios.post(`${API}/getTaskResult`, {
clientKey: API_KEY,
taskId: created.taskId
});
if (result.status === 'ready') return result.solution.gRecaptchaResponse;
}
throw new Error('Solve timed out');
}
CommonJS? Change the import line to const axios = require('axios'); and drop the export — everything else is identical.
Node 18+ has global fetch, FormData and Blob, so image solving needs no packages at all. The endpoint returns the solved text synchronously:
import { readFile } from 'node:fs/promises';
const API_KEY = process.env.CAPTCHAKINGS_KEY;
export async function solveImageCaptcha(path) {
const buffer = await readFile(path);
const form = new FormData();
form.append('captcha', new Blob([buffer]), path);
const res = await fetch('https://captchakings.com/api/process.php', {
method: 'POST',
headers: { Authorization: `Bearer ${API_KEY}` },
body: form
});
const data = await res.json();
if (!data.success) throw new Error(data.error.message);
return {
text: data.data.prediction,
confidence: data.data.confidence,
balance: data.billing.balance_remaining
};
}
console.log(await solveImageCaptcha('captcha.jpg'));
Pair the solver with Puppeteer for full form automation. The challenge never runs in your browser — you just drop the token in:
import puppeteer from 'puppeteer';
import { solveRecaptchaV2 } from './solver.js';
const browser = await puppeteer.launch({ headless: 'new' });
const page = await browser.newPage();
await page.goto('https://example.com/signup');
// Grab the site key from the page, then solve
const siteKey = await page.$eval('.g-recaptcha', el => el.dataset.sitekey);
const token = await solveRecaptchaV2(page.url(), siteKey);
// Inject token into the hidden textarea and submit
await page.evaluate((t) => {
document.getElementById('g-recaptcha-response').value = t;
}, token);
await page.$eval('form', form => form.submit());
await browser.close();
Building a scraping API? Wrap the solver in a route and let your own services call it internally:
import express from 'express';
import { solveRecaptchaV2 } from './solver.js';
const app = express();
app.use(express.json());
app.post('/solve', async (req, res) => {
try {
const token = await solveRecaptchaV2(req.body.url, req.body.siteKey);
res.json({ token });
} catch (err) {
res.status(502).json({ error: err.message });
}
});
app.listen(3000);
Node's event loop makes bulk solving trivial — fire tasks concurrently instead of sequentially:
const jobs = [
{ url: 'https://site-a.com/form', key: 'SITE_KEY_A' },
{ url: 'https://site-b.com/form', key: 'SITE_KEY_B' },
{ url: 'https://site-c.com/form', key: 'SITE_KEY_C' }
];
const tokens = await Promise.all(
jobs.map(j => solveRecaptchaV2(j.url, j.key))
);
console.log(tokens);
| Captcha Type | Endpoint | Result |
|---|---|---|
| Image captcha | captchakings.com/api/process.php | Solved text (synchronous) |
| reCAPTCHA / hCaptcha / AWS WAF | api.captchakings.com/createTask | Token (async, poll getTaskResult) |
| 2Captcha-compatible | captchakings.com/in.php / res.php | Drop-in migration format |
process.env — never commit it to a repo.p-limit) when solving hundreds of tasks so your own process stays predictable.status: "processing" — polling again is the correct behavior.Not yet — but the API is plain JSON over HTTPS, so the axios snippets above are all you need. A full reCAPTCHA solve is under 30 lines.
Same flow as reCAPTCHA with HCaptchaTaskProxyless as the task type. Create the task, poll getTaskResult, use the token. See the hCaptcha solver page for details.
Yes — solve via the API, inject the token into g-recaptcha-response with page.evaluate, submit the form. Full Puppeteer example above.
Image captchas: $0.50 per 1,000 solves, pay-as-you-go. 50 free solves on signup, no credit card. Compare in detail on the pricing page.
50 free solves on signup — test with your own captchas.
Get Your API Key