Scarnox · Blog

Solver de captcha em Node.js: exemplo funcional com fetch (2026)

Um solver de captcha em Node.js é uma única requisição HTTP. O Node 18 e versões posteriores trazem o fetch, então você não precisa de pacote nenhum para chamar a API. Envie o sitekey e a URL da página, aguarde a resposta e coloque o token no formulário. Este guia mostra o fluxo completo para o PopularCaptcha, que a Scarnox resolve hoje de forma proxyless.

Comece com crédito de teste grátis, sem cartão e rode o código abaixo em uma página de teste primeiro.

Requisitos

O módulo solver

O módulo abaixo é uma única função. Ela envia a requisição para a API com um cabeçalho Bearer, cancela após 185 segundos e lança um erro quando errorId não é 0:

// solver.mjs
const API_URL = "https://api.scarnox.com/api/tasks/create";

export async function solveCaptcha(sitekey, pageUrl, { invisible = false } = {}) {
  const body = {
    captcha_type: "PopularCaptchaTaskProxyless",
    site_key: sitekey,
    site_url: pageUrl,
  };
  if (invisible) body.is_invisible = true;

  const res = await fetch(API_URL, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SCARNOX_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
    signal: AbortSignal.timeout(185_000), // a chamada retorna quando o token está pronto
  });

  const data = await res.json().catch(() => null);
  if (!data) throw new Error(`HTTP ${res.status}: response was not JSON`);

  if (data.errorId !== 0) {
    throw new Error(`${data.errorCode}: ${data.errorDescription}`);
  }
  return data.solution.token;
}

Não há polling. A requisição fica aberta até o token estar pronto, e o token está em solution.token em caso de sucesso.

Retentativas

Uma resolução com falha retorna errorId diferente de 0, e você não é cobrado por ela. Um loop curto de retentativas basta para falhas transitórias. Mantenha o número de tentativas baixo, para que um sitekey ou uma URL de página quebrados não consumam tempo à toa:

export async function solveWithRetry(sitekey, pageUrl, attempts = 3) {
  let lastError;
  for (let i = 1; i <= attempts; i++) {
    try {
      return await solveCaptcha(sitekey, pageUrl);
    } catch (err) {
      lastError = err;
      console.warn(`Attempt ${i} failed: ${err.message}`);
      await new Promise((r) => setTimeout(r, 1000 * i));
    }
  }
  throw lastError;
}

Para uma política de erros mais completa, veja tratamento de erros do solver de captcha.

Enviando o token

O token vai para o campo do formulário que o site espera. A maioria das páginas com PopularCaptcha lê h-captcha-response, e muitas também leem g-recaptcha-response. Envie os dois por segurança:

// submit.mjs
import { solveWithRetry } from "./solver.mjs";

const pageUrl = "https://example.com/signup";
const token = await solveWithRetry("YOUR-SITEKEY-UUID", pageUrl);

const form = new URLSearchParams({
  email: "you@example.com",
  "h-captcha-response": token,
  "g-recaptcha-response": token,
});

const res = await fetch(pageUrl, {
  method: "POST",
  body: form,
  redirect: "manual",
});
console.log("Status:", res.status);

Execute com:

SCARNOX_API_KEY=scarnox_YOURAPIKEY node submit.mjs

Cookies e sessões

O fetch puro não mantém cookies entre as requisições. Muitas páginas de cadastro e busca vinculam o captcha a um cookie de sessão, então um token enviado sem o cookie correspondente pode ser rejeitado. Há duas formas de lidar com isso:

Escolha a primeira quando o formulário for simples e o site não rodar muito JavaScript. Escolha a segunda para qualquer coisa mais complexa.

Uma verificação prática: depois do POST, observe o código de status e a URL final. Um redirecionamento para uma página de sucesso geralmente significa que o token foi aceito. Uma página que mostra o widget de novo geralmente significa que ele foi rejeitado, ou que o cookie do GET não foi enviado. Registre o corpo da resposta nas primeiras execuções para saber em qual dos casos você está.

Tempo

O token expira em cerca de dois minutos. Resolva perto do momento do envio. O erro mais comum é resolver no início de um job longo e enviar depois. Resolva e envie imediatamente em seguida. Expiração de token de captcha cobre isso com mais detalhes.

Captchas invisíveis

Se o widget da página tiver data-size="invisible", passe { invisible: true }. A função então envia is_invisible: true junto com a requisição:

const token = await solveCaptcha("YOUR-SITEKEY-UUID", pageUrl, { invisible: true });

Se a página também anexar um callback ao widget, o formulário pode precisar que essa função seja chamada com o token. Leia o script da página para encontrá-la. O guia captcha invisível cobre os padrões.

Scraping com o solver

Às vezes o captcha aparece em uma página que você faz scraping, e não em um formulário que você envia. O mesmo padrão funciona: detecte o widget no HTML, resolva-o e envie-o para a URL para a qual o widget posta. Mantenha a taxa de requisições baixa e verifique os termos do site antes. Faça scraping com responsabilidade: respeite o robots.txt, evite dados pessoais de que você não precisa e não sobrecarregue o servidor.

Preços

A Scarnox cobra por resolução bem-sucedida. Resoluções com falha não são cobradas. Para os valores atuais, veja a página de preços. Para começar, comece com crédito de teste grátis, sem cartão.

Próximos passos