Se a sua integração devolve invalid-input-response em um reCAPTCHA aparentemente comum, a resposta costuma estar em um atributo que quase ninguém procura: data-s. É um token de sessão que o Google injeta no widget em algumas páginas e que precisa viajar junto na requisição. A regra cabe em três linhas:
- Leia o atributo
data-sno widget antes de enviar a tarefa. - Se ele existir, inclua o campo na requisição para
in.php. - Se não existir, envie só
sitekeyepageurl— nada de campo vazio.
Em quais páginas o data-s aparece
Delimitar o escopo economiza horas de depuração: o data-s não existe na maioria das integrações de reCAPTCHA.
| Onde | Frequência | Observação |
|---|---|---|
| Google Search (página de "tráfego incomum") | Sempre | Sem data-s a resolução não fecha |
| YouTube | Às vezes | Aparece em alguns fluxos de verificação |
| Google Play | Às vezes | Verificação de listagem de aplicativos |
| Google Forms | Raramente | Implementações pontuais |
| Sites de terceiros com reCAPTCHA | Praticamente nunca | A integração padrão usa só sitekey e pageurl |
Se o seu pipeline de QA roda contra formulários próprios em staging.example.com, você provavelmente nunca verá o parâmetro. Ele vira assunto quando a requisição esbarra em uma propriedade do Google.
O que é o parâmetro data-s
Um token gerado pelo servidor e embutido no HTML do widget. Amarra o desafio a uma sessão, como um nonce. Cinco características definem o comportamento dele:
- Formato: string em Base64, de 200 a 500 caracteres.
- Validade: uso único, atrelado ao carregamento atual.
- Escopo: específico da sessão, nunca reaproveitável.
- Obrigatoriedade: vale sempre que o atributo existir no widget.
- Renovação: valor novo a cada refresh.
Onde ele fica no HTML
<!-- reCAPTCHA widget with data-s parameter -->
<div class="g-recaptcha"
data-sitekey="6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp"
data-s="AB2grfE8_kyMp3XYRuJo5c..."
data-callback="onCaptchaSolved">
</div>
O atributo fica ao lado do data-sitekey, no mesmo <div> do widget.
Como o data-s se encaixa no fluxo de resolução
O caminho abaixo mostra por onde o valor passa até a validação no Google.
User triggers CAPTCHA (e.g., Google flags unusual search traffic)
↓
Google serves a CAPTCHA page with:
- data-sitekey (site key, same for all Google search CAPTCHAs)
- data-s (session token, unique per page load)
↓
reCAPTCHA widget initializes with both parameters
↓
Challenge completion generates a g-recaptcha-response token
↓
Token is submitted alongside the session reference
↓
Google validates token + session binding
↓
If data-s was not used during solving: "invalid-input-response" or silent failure
A linha final é a que importa: sem o data-s, o token é gerado mas não corresponde à sessão esperada. A falha é silenciosa e o sintoma engana — parece problema de sitekey.
Cinco erros que geram falha silenciosa
| Erro | Sintoma | Correção |
|---|---|---|
Omitir o data-s quando ele existe |
O token é aceito pela API, mas falha na validação | Verifique o atributo antes de montar a requisição |
Enviar data-s quando o widget não tem o atributo |
Erro do solucionador ou requisição recusada | Inclua o campo somente se o atributo existir |
| Reaproveitar o valor entre carregamentos | Token inválido | Extraia um valor novo a cada carregamento |
| Aplicar URL-encoding no valor | Parâmetro malformado | Envie a string Base64 crua, sem codificação extra |
| Usar um valor extraído minutos antes | Incompatibilidade de sessão | Extraia imediatamente antes de enviar a tarefa |
Os dois primeiros respondem pela maior parte dos chamados de suporte.
Como extrair o data-s da página
Três caminhos, do mais barato ao mais caro: HTML bruto em Python, HTML bruto em Node.js e navegador automatizado.
Extração com Python
import requests
from bs4 import BeautifulSoup
import re
def extract_recaptcha_params(url):
"""Extract reCAPTCHA parameters including data-s from a page."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
}
response = requests.get(url, headers=headers, timeout=15)
soup = BeautifulSoup(response.text, "html.parser")
# Find reCAPTCHA widget div
widget = soup.find("div", class_="g-recaptcha")
if not widget:
# Try finding by data-sitekey attribute
widget = soup.find(attrs={"data-sitekey": True})
if not widget:
return {"error": "No reCAPTCHA widget found"}
params = {
"sitekey": widget.get("data-sitekey"),
"data_s": widget.get("data-s"),
"callback": widget.get("data-callback"),
"size": widget.get("data-size"),
"has_data_s": widget.get("data-s") is not None,
}
return params
# Example: Google "unusual traffic" page
params = extract_recaptcha_params("https://www.google.com/sorry/index")
print(params)
# {
# "sitekey": "6LfwuyUT...",
# "data_s": "AB2grfE8_kyMp3...",
# "has_data_s": True
# }
A chave has_data_s centraliza a decisão de incluir ou não o campo.
Extração com Node.js
const axios = require("axios");
const cheerio = require("cheerio");
async function extractRecaptchaParams(url) {
const { data: html } = await axios.get(url, {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) " +
"Chrome/120.0.0.0 Safari/537.36",
},
timeout: 15000,
});
const $ = cheerio.load(html);
const widget = $(".g-recaptcha, [data-sitekey]").first();
if (widget.length === 0) {
return { error: "No reCAPTCHA widget found" };
}
return {
sitekey: widget.attr("data-sitekey"),
dataS: widget.attr("data-s") || null,
callback: widget.attr("data-callback") || null,
hasDataS: !!widget.attr("data-s"),
};
}
extractRecaptchaParams("https://www.google.com/sorry/index")
.then(console.log);
Extração com Selenium, para páginas dinâmicas
Quando a página monta o widget por JavaScript, ler o HTML bruto não basta. Abra a página no navegador automatizado e leia o valor depois da renderização.
from selenium import webdriver
from selenium.webdriver.common.by import By
def extract_data_s_selenium(driver, url):
"""Extract data-s from a dynamically loaded reCAPTCHA page."""
driver.get(url)
# Wait for reCAPTCHA widget to load
import time
time.sleep(3)
try:
widget = driver.find_element(By.CSS_SELECTOR, ".g-recaptcha, [data-sitekey]")
return {
"sitekey": widget.get_attribute("data-sitekey"),
"data_s": widget.get_attribute("data-s"),
}
except Exception:
return {"error": "Widget not found"}
Como enviar o data-s à API da CaptchaAI
Com o valor em mãos, o envio muda pouco: você acrescenta um campo à requisição para in.php e segue com o polling de sempre em res.php.
Python
import requests
import time
API_KEY = "YOUR_API_KEY"
# Step 1: Extract parameters from the CAPTCHA page
sitekey = "6LfwuyUTAAAAAOAmoS0fdqijC2PbbdH4kjq62Y1b"
data_s = "AB2grfE8_kyMp3XYRuJo5c..." # Extracted from data-s attribute
page_url = "https://www.google.com/sorry/index?continue=..."
# Step 2: Submit to CaptchaAI WITH data-s
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"data-s": data_s, # Include data-s parameter
"json": 1,
})
task_id = submit.json()["request"]
# Step 3: Poll for result
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
token = result["request"]
print(f"Token: {token[:60]}...")
# Submit this token to the Google CAPTCHA form
break
Node.js
const axios = require("axios");
async function solveWithDataS(sitekey, dataS, pageUrl) {
const API_KEY = "YOUR_API_KEY";
// Submit with data-s
const { data: submit } = await axios.post(
"https://ocr.captchaai.com/in.php",
new URLSearchParams({
key: API_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageUrl,
"data-s": dataS,
json: 1,
})
);
const taskId = submit.request;
// Poll
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const { data: result } = await axios.get(
"https://ocr.captchaai.com/res.php",
{
params: {
key: API_KEY,
action: "get",
id: taskId,
json: 1,
},
}
);
if (result.status === 1) {
return result.request;
}
}
throw new Error("Timeout");
}
Uma observação para times no Brasil: em workers em sa-east-1 (São Paulo), o RTT soma alguns milissegundos ao polling, mas não muda a regra. O que quebra é o intervalo entre extrair o atributo e enviar a tarefa, não a latência de rede.
Um extrator reutilizável para os dois casos
Em vez de espalhar if pelo código, isole a decisão em uma classe que monta o payload com ou sem data-s. O mesmo worker atende os dois cenários sem ramificação no chamador.
import requests
from bs4 import BeautifulSoup
class RecaptchaExtractor:
"""Extract reCAPTCHA parameters from any page."""
def __init__(self, url, session=None):
self.url = url
self.session = session or requests.Session()
self.params = None
def extract(self):
"""Extract sitekey, data-s, and other parameters."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
}
response = self.session.get(self.url, headers=headers, timeout=15)
soup = BeautifulSoup(response.text, "html.parser")
widget = soup.find(attrs={"data-sitekey": True})
if not widget:
raise ValueError("No reCAPTCHA widget found on page")
self.params = {
"sitekey": widget["data-sitekey"],
"pageurl": self.url,
}
# Include data-s only if present
data_s = widget.get("data-s")
if data_s:
self.params["data-s"] = data_s
return self.params
def build_solver_payload(self, api_key):
"""Build CaptchaAI submission payload with correct parameters."""
if not self.params:
self.extract()
payload = {
"key": api_key,
"method": "userrecaptcha",
"googlekey": self.params["sitekey"],
"pageurl": self.params["pageurl"],
"json": 1,
}
# Only include data-s when it exists
if "data-s" in self.params:
payload["data-s"] = self.params["data-s"]
return payload
# Usage
extractor = RecaptchaExtractor("https://www.google.com/sorry/index?continue=...")
payload = extractor.build_solver_payload("YOUR_API_KEY")
# payload includes data-s only when present on the page
É o padrão que recomendamos para pipelines de QA autorizado: o extrator decide sozinho e o chamador nunca precisa saber se a página era do Google.
Perguntas frequentes
As dúvidas que mais aparecem quando o parâmetro entra no pipeline.
Como sei se a página exige data-s antes de escrever o código?
Abra o DevTools, inspecione o elemento com a classe g-recaptcha e procure o data-s ao lado do data-sitekey. Se não estiver lá, não existe nesse fluxo — uma checagem de dez segundos que evita horas de depuração.
O data-s expira junto com o token do reCAPTCHA?
Não são o mesmo relógio. O data-s vale para o carregamento em que foi gerado; o g-recaptcha-response tem sua própria janela depois de resolvido. Trate os dois como perecíveis: extraia, resolva e envie na mesma execução.
Preciso de um plano específico da CaptchaAI para enviar data-s?
Não. O campo faz parte da requisição padrão de userrecaptcha e está em todos os planos, do BASIC (US$ 15/mês, 5 threads) ao VIP-3 (US$ 7.500/mês, 5.000 threads). O plano define só quantas resoluções simultâneas você tem.
O data-s também existe no reCAPTCHA v3?
O parâmetro é específico do reCAPTCHA em propriedades do Google, e o fluxo do v3 não expõe um widget com esse atributo. Não transporte o campo entre tipos de desafio.
Posso guardar o data-s em cache para reduzir requisições?
Não vale a tentativa. Cada carregamento gera um valor novo, e um valor guardado é, por definição, de outra sessão. O ganho real vem de reduzir o intervalo entre extração e envio.
Em resumo
O data-s aparece em poucas implementações do reCAPTCHA, quase sempre em propriedades do Google. Quando está no widget, extraia o valor e inclua-o na requisição à CaptchaAI; quando não está, envie só sitekey e pageurl.