Integrations

Airtable + CaptchaAI: solução de CAPTCHA acionada por banco de dados

Se uma automação no Airtable trava porque o formulário exige reCAPTCHA, dá para resolver sem sair da base: uma Automation chama a API da CaptchaAI e grava o token de volta no registro. Este guia mostra as duas formas: gatilho por registro (Automation) e lote (Scripting extension).

Quando vale a pena automatizar o CAPTCHA no Airtable

Compensa quando a base já concentra as URLs a processar — por exemplo, editais públicos ou portais de parceiros com login antes da coleta. A Automation detecta o registro, o script envia os parâmetros, a API devolve o token e o registro é atualizado sozinho.

Antes de começar

  • Conta na CaptchaAI com chave de API válida
  • Base no Airtable com permissão para criar Automations e, para lotes, acesso à aba Apps
  • Tabela CAPTCHA Tasks configurada conforme a seção abaixo

Monte a tabela de tarefas

Crie uma tabela CAPTCHA Tasks com estes campos — os nomes precisam bater com o script da próxima etapa:

Nome do campo Tipo Finalidade
URL URL URL da página de destino
Sitekey Texto de linha única sitekey do reCAPTCHA
Status Seleção única valores: pending, solving, solved, failed
Token Texto longo Token do CAPTCHA resolvido
Solved At Data/hora Data e hora em que o CAPTCHA foi resolvido
Error Texto de linha única Mensagem de erro, se a resolução falhar

Passo 1: crie a automação no Airtable

  1. Abra a guia Automações
  2. Clique em Criar automação
  3. Dê um nome, por exemplo "Resolver CAPTCHA no novo registro"

Gatilho

Escolha Quando o registro corresponde às condições, aponte para CAPTCHA Tasks e defina Status é pending. Cobre registros novos e reenvios: para reprocessar um item que falhou, volte o Status para pending.

Passo 2: envie o CAPTCHA para a CaptchaAI

Adicione uma ação → Executar um script e cole o código abaixo. Em resumo, o script:

  • muda o Status para solving assim que começa
  • envia a tarefa ao endpoint in.php e consulta o resultado em res.php
  • grava o token e o horário de resolução de volta no registro
// Airtable Automation Script — Solve CAPTCHA via CaptchaAI

// Input configuration (set in the left panel):
// - recordId: Record ID from trigger
// - sitekey: Sitekey field from trigger
// - pageurl: URL field from trigger
const config = input.config();
const recordId = config.recordId;
const sitekey = config.sitekey;
const pageurl = config.pageurl;

const API_KEY = 'YOUR_API_KEY'; // Use input.config() for security

// Update status to "solving"
const table = base.getTable('CAPTCHA Tasks');
await table.updateRecordAsync(recordId, {
  'Status': { name: 'solving' },
});

try {
  // Step 1: Submit task to CaptchaAI
  const submitUrl = `https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`;

  const submitResponse = await fetch(submitUrl);
  const submitResult = await submitResponse.json();

  if (submitResult.status !== 1) {
    throw new Error(`Submit failed: ${submitResult.request}`);
  }

  const taskId = submitResult.request;
  console.log(`Task submitted: ${taskId}`);

  // Step 2: Poll for result (wait 15 seconds first)
  await new Promise(resolve => setTimeout(resolve, 15000));

  let token = null;
  for (let i = 0; i < 20; i++) {
    const pollUrl = `https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const pollResponse = await fetch(pollUrl);
    const pollResult = await pollResponse.json();

    if (pollResult.status === 1) {
      token = pollResult.request;
      break;
    }

    if (pollResult.request !== 'CAPCHA_NOT_READY') {
      throw new Error(`Solve failed: ${pollResult.request}`);
    }

    await new Promise(resolve => setTimeout(resolve, 5000));
  }

  if (!token) {
    throw new Error('Polling timeout — CAPTCHA not solved in time');
  }

  // Step 3: Update record with solved token
  await table.updateRecordAsync(recordId, {
    'Status': { name: 'solved' },
    'Token': token,
    'Solved At': new Date().toISOString(),
    'Error': '',
  });

  console.log(`CAPTCHA solved for record ${recordId}`);

} catch (error) {
  // Update record with error
  await table.updateRecordAsync(recordId, {
    'Status': { name: 'failed' },
    'Error': error.message,
  });
  console.error(`Failed: ${error.message}`);
}

Configure as variáveis do script

Variável Origem no gatilho
recordId ID do registro
sitekey campo Sitekey
pageurl campo URL

O mesmo padrão resolve imagem (method: base64) e reCAPTCHA v3, já que userrecaptcha cobre v2, v2 Enterprise, v3 e v3 Enterprise.

Passo 3: processe o lote inteiro com a Scripting extension

Para dar conta de muitos registros de uma vez, use a Scripting extension do Airtable, no painel Apps. A lógica é a mesma do script de automação, com duas diferenças:

  • percorre todos os registros com Status pending de uma vez, em vez de reagir a um só
  • roda sob demanda, quando você abre o painel Apps e executa o script
// Batch CAPTCHA Solver — Airtable Scripting Extension
const API_KEY = 'YOUR_API_KEY';
const table = base.getTable('CAPTCHA Tasks');

// Get all pending records
const query = await table.selectRecordsAsync({
  fields: ['URL', 'Sitekey', 'Status'],
});

const pendingRecords = query.records.filter(
  r => r.getCellValueAsString('Status') === 'pending'
);

output.text(`Found ${pendingRecords.length} pending CAPTCHAs`);

for (const record of pendingRecords) {
  const sitekey = record.getCellValueAsString('Sitekey');
  const pageurl = record.getCellValueAsString('URL');

  if (!sitekey || !pageurl) {
    output.text(`Skipping ${record.id} — missing sitekey or URL`);
    continue;
  }

  output.text(`Solving for: ${pageurl}`);

  await table.updateRecordAsync(record.id, {
    'Status': { name: 'solving' },
  });

  try {
    // Submit
    const submitResp = await fetch(
      `https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`
    );
    const submitData = await submitResp.json();

    if (submitData.status !== 1) throw new Error(submitData.request);

    // Poll
    await new Promise(r => setTimeout(r, 15000));
    let token = null;

    for (let i = 0; i < 20; i++) {
      const pollResp = await fetch(
        `https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${submitData.request}&json=1`
      );
      const pollData = await pollResp.json();

      if (pollData.status === 1) { token = pollData.request; break; }
      if (pollData.request !== 'CAPCHA_NOT_READY') throw new Error(pollData.request);
      await new Promise(r => setTimeout(r, 5000));
    }

    if (!token) throw new Error('Timeout');

    await table.updateRecordAsync(record.id, {
      'Status': { name: 'solved' },
      'Token': token,
      'Solved At': new Date().toISOString(),
    });
    output.text(`✓ Solved: ${pageurl}`);

  } catch (e) {
    await table.updateRecordAsync(record.id, {
      'Status': { name: 'failed' },
      'Error': e.message,
    });
    output.text(`✗ Failed: ${e.message}`);
  }
}

output.text('Batch processing complete');

Automation nativa ou Scripting extension: qual escolher

Critério Automation (gatilho por registro) Scripting extension (lote)
Quando roda A cada novo registro com Status pending Sob demanda, quando você executa o script
Volume por execução Um registro por vez Todos os registros pending da tabela
Onde configurar Aba Automações Painel Apps
Melhor para Fluxo contínuo, poucos registros por vez Reprocessar filas grandes de uma só vez

Perguntas frequentes

A CaptchaAI cobra por solve ou por thread?

Por thread simultânea, não por solve:

  • BASIC: US$ 15/mês, 5 threads em paralelo
  • Solves ilimitados dentro de cada thread contratada

Esse fluxo funciona com reCAPTCHA v3, ou só v2?

Sim, funciona com os dois: userrecaptcha cobre reCAPTCHA v2, v2 Enterprise, v3 e v3 Enterprise. Só troque a sitekey salva no campo Sitekey.

Como guardo a chave de API sem deixá-la exposta no script?

Use uma variável de entrada no painel da ação de script — nunca escreva a chave no código. Na Scripting extension, peça a chave com input.textAsync().

Os registros salvos no Airtable entram nas regras da LGPD?

Se a tabela guardar dados pessoais junto com o token, sim. Antes de publicar:

  • defina prazo de retenção para os registros
  • restrinja o acesso ao painel a quem precisa dele

Não é orientação jurídica; em casos sensíveis, envolva o compliance.

Erros comuns e como corrigir

Problema Causa Correção
A automação não dispara Registro não bate com a condição Status = pending Confira se o Status é exatamente pending
fetch is not defined Airtable Scripting às vezes exige remoteFetchAsync Troque fetch por remoteFetchAsync
Script estourou o tempo limite Scripts de automação têm limite de 30 s Reduza as iterações de polling e aumente a espera inicial para 20 s
A atualização do registro falha Nome de campo não bate com a tabela Confirme se os nomes em updateRecordAsync batem com a tabela
Chave de API exposta no script Chave de API escrita direto no código Use input.config() com uma variável de entrada secreta

Artigos relacionados

Veja também como resolver o callback do reCAPTCHA v2 pela API, reCAPTCHA v2 e Turnstile no mesmo site e como funciona o callback do reCAPTCHA v2.

Próximos passos

Pegue sua chave de API da CaptchaAI e configure a automação ainda hoje. O mesmo padrão vale para o Script do Google Apps, o Zapier e o Make (Integromat).

Os comentários estão desativados para este artigo.