reCAPTCHA Invisible ne présente aucune case à cocher : le défi se déclenche quand l'utilisateur clique sur un bouton ou envoie un formulaire, puis se joue entièrement en arrière-plan. La page ne continue que lorsque le token est vérifié. Pour le résoudre via l'API CaptchaAI, la recette tient en deux gestes : envoyez exactement la même requête userrecaptcha que pour reCAPTCHA v2, mais ajoutez le paramètre invisible=1, puis réinjectez le token en appelant la fonction de callback de la page.
Toute la subtilité de l'intégration se trouve là, dans la façon d'injecter le token. Contrairement à un reCAPTCHA v2 classique, la plupart des implémentations invisibles n'attendent pas une simple valeur dans le champ masqué g-recaptcha-response : elles déclenchent une fonction de callback. Repérer ce callback et l'appeler avec le token obtenu, c'est ce qui fait réellement avancer la page — le reste du flux reste identique à un v2 standard.
Un doute entre Invisible et v2 standard ? Les critères de détection sont détaillés dans reCAPTCHA v2 vs Invisible. Le flux, lui, tient toujours en quatre temps : repérer la signature invisible, envoyer la tâche avec invisible=1, interroger le résultat, puis appeler le callback pour débloquer la page.
Ce qu'il vous faut avant de commencer
Réunissez quatre éléments avant de lancer votre premier appel :
- Clé API CaptchaAI — disponible sur captchaai.com/api.php ;
- Sitekey — lu dans
data-sitekeysur le widget ou le bouton ; - URL de la page — l'adresse complète où s'exécute le CAPTCHA invisible ;
- Navigateur piloté — Selenium ou Puppeteer pour exécuter le callback.
Étape 1 : repérer un reCAPTCHA Invisible dans la page
Trois signatures HTML trahissent un reCAPTCHA Invisible. Cherchez-les dans le code source de la page avant d'écrire la moindre ligne d'intégration :
<!-- Option 1: div with data-size="invisible" -->
<div class="g-recaptcha" data-sitekey="6LdKlZEU..." data-size="invisible" data-callback="onSubmit"></div>
<!-- Option 2: button with data-sitekey (invisible by default) -->
<button data-sitekey="6LdKlZEU..." data-callback="onSubmit">Submit</button>
<!-- Option 3: programmatic execution -->
<script>
grecaptcha.execute('6LdKlZEU...', {action: 'submit'});
</script>
Concrètement, trois indices suffisent à trancher :
- un attribut
data-size="invisible"sur le widget ; - un bouton porteur d'un
data-sitekeysans case à cocher visible ; - un appel
grecaptcha.execute()déclenché sans conteneur.
Dans ces trois cas, vous avez affaire à un reCAPTCHA Invisible, pas à un v2 à case à cocher. Notez au passage le sitekey et le nom du callback : vous en aurez besoin aux étapes 2 et 4.
Étape 2 : envoyer la tâche à CaptchaAI
Transmettez le sitekey et l'URL de la page à l'endpoint in.php. Le paramètre décisif est invisible=1 : sans lui, CaptchaAI traite la demande comme un v2 standard et le token risque d'être refusé côté serveur.
import requests
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": "6LdKlZEUAAAAAPoxm...",
"pageurl": "https://example.com/signup",
"invisible": 1,
"json": 1
})
task_id = response.json()["request"]
const params = new URLSearchParams({
key: "YOUR_API_KEY", method: "userrecaptcha",
googlekey: "6LdKlZEUAAAAAPoxm...",
pageurl: "https://example.com/signup",
invisible: 1, json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
const { request: taskId } = await res.json();
Le principe est le même quel que soit le langage : une requête GET sur in.php, les paramètres en query string, une réponse JSON. La réponse vous rend un identifiant de tâche : c'est lui que vous allez interroger à l'étape suivante. Voici le rôle des paramètres qui changent par rapport à un OCR simple :
| Paramètre | Rôle |
|---|---|
method=userrecaptcha |
Indique un défi de la famille reCAPTCHA |
googlekey |
Le sitekey lu dans la page cible |
invisible=1 |
Force le traitement en mode invisible |
pageurl |
L'URL exacte où le défi s'exécute |
Étape 3 : interroger le résultat (polling)
La résolution n'est pas instantanée. Interrogez res.php toutes les cinq secondes jusqu'à recevoir le token, en gardant le code CAPCHA_NOT_READY comme signal d'attente et non comme erreur. Toute autre valeur inattendue doit interrompre la boucle et remonter l'erreur.
import time
for _ in range(40):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY", "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
token = result["request"]
break
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Error: {result['request']}")
Étape 4 : injecter le token via le callback
C'est l'étape qui distingue vraiment l'Invisible du v2. La page attend une fonction de callback, pas seulement une valeur de champ masqué. Récupérez le nom du callback depuis data-callback, puis appelez-le avec le token. Si aucun callback n'est déclaré, repliez-vous sur le champ g-recaptcha-response et soumettez le formulaire.
Voici les deux versions, avec Selenium côté Python puis Puppeteer côté Node.js :
# Selenium example
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com/signup")
# Find the callback name
callback = driver.execute_script("""
var el = document.querySelector('[data-callback]');
if (el) return el.getAttribute('data-callback');
var btn = document.querySelector('[data-sitekey]');
if (btn) return btn.getAttribute('data-callback');
return null;
""")
# Execute the callback with the token
if callback:
driver.execute_script(f"window['{callback}']('{token}');")
else:
# Fallback: fill hidden field and submit
driver.execute_script(f"""
document.getElementById('g-recaptcha-response').innerHTML = '{token}';
document.querySelector('form').submit();
""")
// Puppeteer example
await page.evaluate((token) => {
const el = document.querySelector('[data-callback]') || document.querySelector('[data-sitekey]');
const callbackName = el?.getAttribute('data-callback');
if (callbackName && window[callbackName]) {
window[callbackName](token);
} else {
document.getElementById('g-recaptcha-response').innerHTML = token;
document.querySelector('form').submit();
}
}, token);
Une fonction complète prête à l'emploi
Voici l'envoi et le polling regroupés dans une seule fonction réutilisable. L'injection du token reste à déclencher côté navigateur, avec le modèle de l'étape 4.
import requests
import time
def solve_invisible_recaptcha(api_key, sitekey, page_url):
submit = requests.get("https://ocr.captchaai.com/in.php", params={
"key": api_key, "method": "userrecaptcha", "googlekey": sitekey,
"pageurl": page_url, "invisible": 1, "json": 1
}).json()
if submit.get("status") != 1:
raise RuntimeError(f"Submit error: {submit.get('request')}")
task_id = submit["request"]
for _ in range(40):
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:
return result["request"]
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve error: {result.get('request')}")
raise TimeoutError("Timed out")
token = solve_invisible_recaptcha("YOUR_API_KEY", "6LdKlZEU...", "https://example.com/signup")
Un cas concret : le formulaire d'inscription d'un SaaS
Prenons une situation fréquente dans les équipes francophones : le formulaire d'inscription ou de contact d'un SaaS, protégé par un reCAPTCHA Invisible, que vous devez couvrir dans vos tests QA de bout en bout. Le widget reste inerte tant que l'utilisateur n'a pas cliqué sur « Créer un compte » ; votre script de recette doit donc résoudre le défi, puis déclencher le callback avant de valider le reste du parcours. C'est exactement l'enchaînement des étapes 2 à 4 : envoi avec invisible=1, polling, appel du callback avec le token.
Deux réflexes utiles quand vous industrialisez ce type de test :
- Capacité — chaque tâche en vol occupe un thread. Le plan BASIC ($15/mois, 5 threads) autorise cinq résolutions simultanées ; ne montez de palier que si vos exécutions se chevauchent réellement.
- Conformité — limitez les données personnelles manipulées dans ces scénarios et vérifiez vos obligations RGPD ; un environnement de staging avec des comptes fictifs vous évite de traiter des données clients pour rien.
Exemple entièrement exécutable
Besoin d'un projet complet, avec configuration de l'environnement, polling, nouvelles tentatives et gestion des erreurs déjà câblés ?
Voir l'exemple exécutable complet sur GitHub →
Dépannage
Quand la page ne repart pas, l'erreur se situe presque toujours entre la résolution et l'injection. Les cas les plus fréquents :
| Problème | Cause probable | Correctif |
|---|---|---|
| Token accepté mais formulaire bloqué | Mauvais nom de callback | Relire data-callback et appeler la bonne fonction |
| Token refusé côté serveur | invisible=1 oublié |
Ajouter le paramètre et relancer la tâche |
| Aucun callback trouvé | Widget sans data-callback |
Remplir g-recaptcha-response puis soumettre |
| Résolution qui expire | Polling trop court | Élargir la boucle ou l'intervalle de nouvelles tentatives |
FAQ
Le token d'un reCAPTCHA Invisible expire-t-il ?
Oui. Un token reCAPTCHA reste valide environ deux minutes. Résolvez et injectez-le dans la foulée : si votre script laisse passer trop de temps entre la résolution et l'appel du callback, il faudra relancer une nouvelle résolution.
Peut-on résoudre un reCAPTCHA Invisible Enterprise ?
Oui. Ajoutez à la fois invisible=1 et enterprise=1 à votre requête. Le reste du flux — envoi, polling, injection par le callback — reste strictement identique.
Faut-il obligatoirement un navigateur pour injecter le token ?
Pour déclencher un callback JavaScript, oui : Selenium ou Puppeteer restent le moyen le plus fiable. En revanche, si le formulaire est soumis côté serveur et lit simplement le champ g-recaptcha-response, vous pouvez transmettre le token directement dans votre requête POST, sans navigateur.
Guides associés
- Comment fonctionne reCAPTCHA Invisible
- Erreurs courantes du reCAPTCHA Invisible
- reCAPTCHA v2 vs Invisible
- Résoudre le callback reCAPTCHA v2 via l'API
Lancez votre première résolution
Récupérez votre clé API sur captchaai.com/api.php. Reprenez votre code de résolution reCAPTCHA v2, ajoutez invisible=1 à la requête et réutilisez le modèle d'injection par callback présenté plus haut.