Tutorials

Como resolver CAPTCHA em automação de navegador mobile

Se a sua automação resolve CAPTCHA sem problema no desktop mas trava assim que você emula um iPhone ou roda o Chrome for Android via ADB, o motivo quase nunca é o CAPTCHA em si — é o layout responsivo, o campo do token com outro nome, ou o User-Agent que muda o desafio renderizado na tela. A CaptchaAI resolve com base na sitekey e na URL da página: o contexto mobile não muda o método de resolução, só onde e como você extrai a sitekey e injeta o token de volta.

Este guia mostra dois caminhos testados para resolver reCAPTCHA v2 em contexto mobile. Nos dois, a lógica de envio e consulta à CaptchaAI é a mesma do desktop — o que muda é a extração da sitekey e a injeção do token numa tela pensada para toque.

  • Emulação no Playwright — perfil de dispositivo pronto (iPhone 13), sem hardware físico, ideal para CI.
  • Selenium com Chrome DevTools Protocol — emulação mobile via mobileEmulation, direto no seu pipeline Node.js existente.

Cenário: reCAPTCHA v2 em um formulário mobile

Você está automatizando o envio de um formulário em um site otimizado para mobile que usa reCAPTCHA v2. O site detecta o User-Agent do dispositivo e renderiza um layout de CAPTCHA específico para telas pequenas. A tarefa é resolver o desafio e enviar o formulário a partir de um contexto de navegador mobile — emulado ou em um dispositivo Android real conectado via ADB.


Desktop vs. mobile: o que muda no desafio CAPTCHA

Fator Desktop Mobile Impacto no CAPTCHA
User-Agent Chrome/Firefox desktop Mobile Safari/Chrome mobile Alguns sites servem uma configuração de CAPTCHA diferente por dispositivo
Viewport 1920×1080 ou maior 390×844 O widget do CAPTCHA pode renderizar de forma diferente
Eventos de interação Eventos de mouse Eventos de toque Alguns CAPTCHAs validam o tipo de interação
Rede Banda larga 4G/5G Timeouts mais longos podem ser necessários

Em execuções contra rede móvel real — fora de um datacenter — a variação de RTT em conexões 4G costuma justificar um timeout de polling mais folgado do que os 5 segundos usados no desktop, principalmente em suítes que testam vários domínios em lote.


Abordagem 1: emulação mobile do Playwright (Python)

A emulação de dispositivo do Playwright é o caminho mais direto para automação mobile com resolução de CAPTCHA — sem precisar de hardware físico. O código abaixo abre a página com o perfil do iPhone 13, extrai a sitekey do widget reCAPTCHA, resolve via CaptchaAI e injeta o token antes de enviar o formulário:

# playwright_mobile_captcha.py
import asyncio
import httpx
from playwright.async_api import async_playwright

API_KEY = "YOUR_API_KEY"

async def solve_recaptcha(sitekey: str, pageurl: str) -> str:
    """Submit reCAPTCHA v2 to CaptchaAI and poll for result."""
    async with httpx.AsyncClient(timeout=180) as client:
        # Submit task
        resp = await client.get(
            "https://ocr.captchaai.com/in.php",
            params={
                "key": API_KEY,
                "method": "userrecaptcha",
                "googlekey": sitekey,
                "pageurl": pageurl,
                "json": "1",
            },
        )
        result = resp.json()
        if result["status"] != 1:
            raise Exception(f"Submit failed: {result['request']}")

        task_id = result["request"]

        # Poll for result
        for _ in range(30):
            await asyncio.sleep(5)
            poll = await client.get(
                "https://ocr.captchaai.com/res.php",
                params={
                    "key": API_KEY,
                    "action": "get",
                    "id": task_id,
                    "json": "1",
                },
            )
            poll_result = poll.json()
            if poll_result["status"] == 1:
                return poll_result["request"]
            if poll_result["request"] != "CAPCHA_NOT_READY":
                raise Exception(f"Solve failed: {poll_result['request']}")

        raise Exception("Polling timeout")

async def main():
    async with async_playwright() as p:
        # Launch with iPhone 13 emulation
        iphone = p.devices["iPhone 13"]
        browser = await p.chromium.launch(headless=False)
        context = await browser.new_context(**iphone)
        page = await context.new_page()

        await page.goto("https://example.com/mobile-form")
        await page.wait_for_selector(".g-recaptcha", timeout=10000)

        # Extract sitekey
        sitekey = await page.get_attribute(".g-recaptcha", "data-sitekey")
        pageurl = page.url
        print(f"Found sitekey: {sitekey}")

        # Solve via CaptchaAI
        token = await solve_recaptcha(sitekey, pageurl)
        print(f"Token received: {token[:50]}...")

        # Inject token
        await page.evaluate(f"""
            document.getElementById('g-recaptcha-response').value = '{token}';
            document.getElementById('g-recaptcha-response').style.display = '';
        """)

        # Trigger callback if it exists
        await page.evaluate(f"""
            try {{
                const clients = ___grecaptcha_cfg.clients;
                Object.keys(clients).forEach(k => {{
                    Object.keys(clients[k]).forEach(j => {{
                        if (clients[k][j] && clients[k][j].callback) {{
                            clients[k][j].callback('{token}');
                        }}
                    }});
                }});
            }} catch(e) {{}}
        """)

        # Submit form
        await page.click('button[type="submit"]')
        await page.wait_for_load_state("networkidle")
        print("Form submitted successfully")

        await browser.close()

asyncio.run(main())

Abordagem 2: Selenium com emulação mobile (JavaScript)

Para pipelines Node.js, o Selenium com emulação mobile do Chrome DevTools Protocol resolve o mesmo problema sem trocar de stack. A diferença em relação ao desktop está só na configuração mobileEmulation, que define viewport e User-Agent antes de abrir o navegador:

// selenium_mobile_captcha.js
const { Builder, By, until } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const axios = require('axios');

const API_KEY = 'YOUR_API_KEY';

async function solveCaptcha(sitekey, pageurl) {
  // Submit task
  const submitResp = await axios.get('https://ocr.captchaai.com/in.php', {
    params: {
      key: API_KEY,
      method: 'userrecaptcha',
      googlekey: sitekey,
      pageurl: pageurl,
      json: '1',
    },
  });

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

  const taskId = submitResp.data.request;

  // Poll for result
  for (let i = 0; i < 30; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const pollResp = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: API_KEY, action: 'get', id: taskId, json: '1' },
    });

    if (pollResp.data.status === 1) return pollResp.data.request;
    if (pollResp.data.request !== 'CAPCHA_NOT_READY') {
      throw new Error(`Solve failed: ${pollResp.data.request}`);
    }
  }
  throw new Error('Polling timeout');
}

async function main() {
  // Configure mobile emulation
  const mobileEmulation = {
    deviceMetrics: { width: 390, height: 844, pixelRatio: 3.0 },
    userAgent:
      'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) ' +
      'AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
  };

  const options = new chrome.Options();
  options.setMobileEmulation(mobileEmulation);

  const driver = await new Builder()
    .forBrowser('chrome')
    .setChromeOptions(options)
    .build();

  try {
    await driver.get('https://example.com/mobile-form');
    await driver.wait(until.elementLocated(By.css('.g-recaptcha')), 10000);

    // Extract sitekey
    const captchaEl = await driver.findElement(By.css('.g-recaptcha'));
    const sitekey = await captchaEl.getAttribute('data-sitekey');
    const pageurl = await driver.getCurrentUrl();

    console.log(`Sitekey: ${sitekey}`);

    // Solve CAPTCHA
    const token = await solveCaptcha(sitekey, pageurl);
    console.log(`Token: ${token.substring(0, 50)}...`);

    // Inject token
    await driver.executeScript(`
      document.getElementById('g-recaptcha-response').value = arguments[0];
    `, token);

    // Submit form
    await driver.findElement(By.css('button[type="submit"]')).click();
    console.log('Form submitted');
  } finally {
    await driver.quit();
  }
}

main().catch(console.error);

Solução de problemas comuns

Problema Causa Correção
CAPTCHA não renderiza na emulação mobile O site detecta a emulação pelo navigator.platform Defina o override de plataforma no Chrome DevTools Protocol
Textarea g-recaptcha-response não encontrada O layout mobile usa uma renderização diferente do CAPTCHA Busque o textarea pelo atributo name, não pelo id
Envio ao endpoint de QA funciona, mas o formulário continua falhando O servidor valida a consistência do User-Agent Use o mesmo User-Agent na resolução e no envio do formulário
Carregamento lento das páginas na emulação Páginas com muitos recursos Use a flag --disable-images do Chrome para acelerar o carregamento

Dica: se a automação também usa proxy para simular localização, aplique o mesmo proxy na chamada à CaptchaAI — misturar o IP do navegador com o IP da resolução costuma disparar uma verificação extra no site de destino.

Quantas threads sua automação mobile precisa

A cobrança da CaptchaAI é por thread concorrente, não por CAPTCHA resolvido — cada thread aceita a próxima tarefa assim que a anterior termina, sem limite de resoluções dentro do plano. Isso importa em automação mobile porque cada emulador ou dispositivo ativo consome uma thread enquanto resolve; uma suíte que sobe vários emuladores Android e iOS em paralelo no CI pode saturar rápido um plano pequeno.

  • QA com um ou dois emuladores em paralelo: o BASIC (US$ 15/mês, 5 threads) costuma bastar.
  • Farms de dispositivos ou execuções mobile em lote no CI: o ADVANCE (US$ 90/mês, 50 threads) evita fila de espera entre execuções simultâneas.

Perguntas frequentes

Emulação ou dispositivo real: qual usar para testar CAPTCHA mobile?

Para desenvolvimento e CI/CD, a emulação é mais rápida de configurar e não depende de hardware. Um dispositivo real via Appium ou ADB fica melhor reservado para a validação final antes de produção, quando o sinal de navegador do dispositivo físico importa.

A CaptchaAI precisa saber que o desafio veio de um navegador mobile?

Não. A resolução usa a sitekey e a URL da página — a distinção entre mobile e desktop não entra no processo de resolução em nenhum momento.

Que plano da CaptchaAI faz sentido para automação mobile em paralelo?

Depende de quantos emuladores ou dispositivos rodam ao mesmo tempo. Como a cobrança é por thread concorrente, com resoluções ilimitadas por thread, o BASIC (US$ 15/mês, 5 threads) atende pipelines pequenos; suítes maiores costumam migrar para o ADVANCE (US$ 90/mês, 50 threads) ou o PREMIUM (US$ 170/mês, 100 threads).

Por que o CAPTCHA some quando ativo a emulação de um Android ou iPhone no DevTools?

Na maioria dos casos o site detecta a emulação comparando navigator.platform com o User-Agent declarado e simplesmente não renderiza o widget. Definir o override de plataforma no Chrome DevTools Protocol junto com o User-Agent mobile resolve a maior parte desses casos.

Preciso considerar a LGPD ao registrar dados de dispositivo nos testes?

Se os logs de QA guardam User-Agent, IP ou outros identificadores de dispositivo, vale tratar isso como dado pessoal para fins da LGPD — use dados fictícios sempre que possível e evite reter logs de teste além do necessário.


Artigos relacionados

Próximos passos

Comece a automatizar fluxos de CAPTCHA mobile — obtenha sua chave de API da CaptchaAI e integre com a sua stack de automação mobile.

Guias relacionados:

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