Não, resolver um CAPTCHA em produção não exige um navegador. Puppeteer e Playwright importam quando a página exige renderização JavaScript — o CAPTCHA é resolvido à parte, pela API da CaptchaAI. Com Axios e HTTP puro, você envia o desafio, aguarda o token e segue para login, formulário ou coleta de dados. O ganho prático aparece em produção: menos memória por worker, deploy mais simples (sem Chromium empacotado) e um fluxo de erros que você trata como qualquer chamada HTTP comum.
O que você precisa antes de começar
| Requisito | Detalhes |
|---|---|
| Node.js | 16+ |
| axios | 1.x |
| Chave de API CaptchaAI | Pegue um aqui |
npm install axios
Monte o cliente CaptchaAI para Axios
Esta classe centraliza envio (in.php), consulta de resultado (res.php) e saldo — reaproveite-a abaixo.
const axios = require("axios");
class CaptchaAI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = "https://ocr.captchaai.com";
}
async submit(params) {
params.key = this.apiKey;
const resp = await axios.get(`${this.baseUrl}/in.php`, { params });
const text = resp.data;
if (!String(text).startsWith("OK|")) {
throw new Error(`Submit failed: ${text}`);
}
return String(text).split("|")[1];
}
async poll(taskId, timeoutMs = 300000) {
const deadline = Date.now() + timeoutMs;
const params = { key: this.apiKey, action: "get", id: taskId };
while (Date.now() < deadline) {
await new Promise((r) => setTimeout(r, 5000));
const resp = await axios.get(`${this.baseUrl}/res.php`, { params });
const text = String(resp.data);
if (text === "CAPCHA_NOT_READY") continue;
if (text.startsWith("OK|")) return text.split("|").slice(1).join("|");
throw new Error(`Solve failed: ${text}`);
}
throw new Error(`Timeout after ${timeoutMs}ms for task ${taskId}`);
}
async solve(params, timeoutMs = 300000) {
const taskId = await this.submit(params);
return this.poll(taskId, timeoutMs);
}
async getBalance() {
const resp = await axios.get(`${this.baseUrl}/res.php`, {
params: { key: this.apiKey, action: "getbalance" },
});
return parseFloat(resp.data);
}
}
module.exports = CaptchaAI;
A classe acima separa três responsabilidades que costumam ficar misturadas em scripts avulsos: enviar a tarefa (submit), consultar o resultado em intervalos (poll) e expor o saldo (getBalance). Isso facilita reaproveitar o mesmo cliente em vários pontos do código — um worker de fila, uma rota de API interna, um script de QA — sem duplicar a lógica de requisição. Trate os erros lançados por submit e poll como você trataria qualquer falha de rede: com retentativa controlada, nunca em loop infinito.
Resolva reCAPTCHA v2 direto pela API (sem navegador)
Com o cliente pronto, resolva o reCAPTCHA v2 enviando os parâmetros certos:
const CaptchaAI = require("./captchaai");
async function main() {
const solver = new CaptchaAI(process.env.CAPTCHAAI_API_KEY);
// Solve the CAPTCHA without opening any browser
const token = await solver.solve({
method: "userrecaptcha",
googlekey: "6Le-wvkS...",
pageurl: "https://staging.example.com/qa-login",
});
// Submit form with the token using Axios
const resp = await axios.post("https://staging.example.com/qa-login", {
username: "user",
password: "pass",
"g-recaptcha-response": token,
});
console.log(`Login response: ${resp.status}`);
}
main().catch(console.error);
Guarde CAPTCHAAI_API_KEY em variável de ambiente ou no seu gerenciador de segredos — nunca no código-fonte versionado. Repare também que pageurl precisa refletir a URL real onde o desafio aparece: a CaptchaAI valida esse campo contra a sitekey, então usar um valor genérico causa falha na verificação do lado do site-alvo, não apenas na resolução.
Resolva o Cloudflare Turnstile sem abrir navegador
O Turnstile segue o mesmo padrão — troque apenas method e a chave:
const token = await solver.solve({
method: "turnstile",
sitekey: "0x4AAAAA...",
pageurl: "https://example.com",
});
// Submit with Turnstile token
const resp = await axios.post("https://example.com/api/verify", {
"cf-turnstile-response": token,
data: "payload",
});
Como o Turnstile normalmente roda em segundo plano, sem interação visível do usuário, o cliente Axios não precisa simular clique nem esperar animação — apenas envia sitekey e pageurl e aguarda o token, exatamente como no reCAPTCHA v2.
Resolva CAPTCHAs de imagem com OCR
Envie o arquivo em base64 e receba o texto já resolvido:
const fs = require("fs");
const imageBuffer = fs.readFileSync("captcha.png");
const imageB64 = imageBuffer.toString("base64");
const text = await solver.solve({
method: "base64",
body: imageB64,
});
console.log(`CAPTCHA text: ${text}`);
// Submit form with solved text
const resp = await axios.post("https://example.com/verify", {
captcha: text,
other_data: "value",
});
Não é preciso redimensionar nem pré-processar a imagem antes de codificar em base64 — envie o arquivo como veio da página. Se o desafio expira rápido (imagens de login costumam ter janela curta), capture o arquivo o mais perto possível da chamada solve, para não gastar segundos do prazo entre o download e o envio.
Do CAPTCHA ao dado extraído: fluxo completo de web scraping
Junte tudo: buscar a página, extrair a sitekey, resolver o CAPTCHA e reenviar o formulário:
const CaptchaAI = require("./captchaai");
const axios = require("axios");
const cheerio = require("cheerio");
async function scrapeProtectedPage(url) {
const solver = new CaptchaAI(process.env.CAPTCHAAI_API_KEY);
// Step 1: Fetch the page
const page = await axios.get(url);
const $ = cheerio.load(page.data);
// Step 2: Extract the reCAPTCHA site key
const siteKey = $(".g-recaptcha").attr("data-sitekey");
if (!siteKey) {
console.log("No CAPTCHA found, returning page content");
return page.data;
}
// Step 3: Solve the CAPTCHA
console.log(`Solving CAPTCHA for ${url}...`);
const token = await solver.solve({
method: "userrecaptcha",
googlekey: siteKey,
pageurl: url,
});
// Step 4: Submit form with token
const formAction = $("form").attr("action") || url;
const formData = {};
$("form input").each((_, el) => {
const name = $(el).attr("name");
const value = $(el).attr("value") || "";
if (name) formData[name] = value;
});
formData["g-recaptcha-response"] = token;
const result = await axios.post(formAction, new URLSearchParams(formData), {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
return result.data;
}
scrapeProtectedPage("https://example.com/data")
.then((data) => console.log("Success:", typeof data))
.catch(console.error);
Nota para produção no Brasil: workers em sa-east-1 (São Paulo) reduzem a latência até a API da CaptchaAI. Se o fluxo grava dados pessoais da página, respeite a LGPD (RGPD em Portugal) antes de persistir o que for além do teste.
Resolução em paralelo: várias URLs ao mesmo tempo
Dispare várias resoluções com Promise.all — cada requisição consome uma thread do plano:
async function solveBatch(urls, siteKey) {
const solver = new CaptchaAI(process.env.CAPTCHAAI_API_KEY);
const promises = urls.map(async (url) => {
try {
const token = await solver.solve({
method: "userrecaptcha",
googlekey: siteKey,
pageurl: url,
});
return { url, token, error: null };
} catch (error) {
return { url, token: null, error: error.message };
}
});
const results = await Promise.all(promises);
const solved = results.filter((r) => r.token);
console.log(`Solved ${solved.length}/${urls.length}`);
return results;
}
O paralelismo real que você consegue depende das threads do seu plano, não do código: se o plano tem 5 threads, disparar 50 promessas ao mesmo tempo só faz as excedentes esperarem na fila da CaptchaAI. Dimensione o Promise.all (ou use um limitador como p-limit) para não ultrapassar o número de threads contratado.
Solução de problemas comuns
| Erro | Causa | Correção |
|---|---|---|
AxiosError: getaddrinfo ENOTFOUND |
Problema de DNS | Verifique a conectividade da rede |
Submit failed: ERROR_WRONG_USER_KEY |
Chave de API incorreta | Verifique a chave no painel |
Submit failed: ERROR_ZERO_BALANCE |
Sem saldo | Adicione saldo à conta |
| Token rejeitado pelo site de destino | O token expirou | Envie o token em até 60 segundos |
Perguntas frequentes
hCaptcha funciona com a CaptchaAI via Axios?
Não. hCaptcha e FunCaptcha (Arkose Labs) continuam fora do catálogo suportado. A API cobre reCAPTCHA v2/v3, Turnstile e Challenge, GeeTest v3, CAPTCHAs de imagem/grade e BLS — esse é o conjunto que o cliente Axios acima resolve de ponta a ponta.
Preciso trocar de plano para rodar resoluções em paralelo?
Depende do volume. BASIC (US$ 15/mês, 5 threads) cobre lotes pequenos; ADVANCE (US$ 90/mês, 50 threads) ou um VIP escalam o mesmo código sem mudar uma linha — só o número de threads simultâneas muda.
Por que evitar Selenium ou Puppeteer só para resolver o CAPTCHA?
Um navegador consome 200–500 MB de RAM por instância; o cliente Axios usa poucos MB — em lotes com várias URLs isso se multiplica rápido e encarece o worker. Reserve o navegador para quando a própria página, e não o CAPTCHA, exigir JavaScript.
Ainda preciso de um navegador em algum ponto?
Só se a página exigir renderização de JavaScript para montar o conteúdo. Para o CAPTCHA em si, nunca — a CaptchaAI resolve remotamente e você reenvia o token pela mesma requisição Axios que já está usando.