Les deux sont des variantes de reCAPTCHA v2 utilisant la même technologie sous-jacente. La version checkbox affiche "Je ne suis pas un robot" et peut présenter des grilles d'images. La version invisible se déclenche automatiquement lors des actions de l'utilisateur (clic sur un bouton, soumission de formulaire ou chargement de page) sans widget visible. Pour la résolution de CaptchaAI, la seule différence est d'ajouter invisible=1 à votre demande, mais le processus d'injection de jetons diffère considérablement.
Comparaison côte à côte
| Caractéristique | v2 Case à cocher | v2 invisible |
|---|---|---|
| Widget visible | Oui — case à cocher « Je ne suis pas un robot » | Non – masqué aux utilisateurs |
| Mécanisme de déclenchement | L'utilisateur clique sur la case à cocher | Clic sur un bouton, soumission de formulaire ou chargement de page |
| Défi d'image | S'affiche lorsque Google soupçonne un bot | Pop-up dans le coin inférieur droit en cas de suspicion |
| Expérience utilisateur | Frottement modéré | Faible friction/zero |
| Mise en œuvre | Ajouter le div g-recaptcha à la page |
Ajoutez data-callback au bouton ou grecaptcha.execute() |
| Format de clé de site | Identique à l'invisible | Identique à la case à cocher |
| Champ de jeton | g-recaptcha-response |
g-recaptcha-response |
| Fonction de rappel | Facultatif | Presque toujours requis |
| Méthode CaptchaAI | method=userrecaptcha |
method=userrecaptcha + invisible=1 |
| Durée de vie du jeton | 120 secondes | 120 secondes |
| Résoudre le temps | 10-30 secondes | 10-25 secondes |
Comment chacun apparaît dans le HTML
v2 Case à cocher
<!-- Standard checkbox widget -->
<div class="g-recaptcha"
data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
data-callback="onSubmit">
</div>
<!-- Widget renders as: -->
<!-- [✓] I'm not a robot reCAPTCHA logo -->
L'utilisateur voit et interagit avec la case à cocher. Si Google est suspect, un défi de grille d'images apparaît en ligne.
v2 invisible
<!-- Pattern 1: Invisible widget on a button -->
<button class="g-recaptcha"
data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
data-callback="onSubmit"
data-size="invisible">
Submit
</button>
<!-- Pattern 2: Invisible div (programmatic trigger) -->
<div class="g-recaptcha"
data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
data-size="invisible"
data-callback="onSubmit">
</div>
<!-- Pattern 3: Programmatic render -->
<script>
grecaptcha.render('submit-btn', {
sitekey: '6Le-wvkSAAAAAPBMRTvw...',
callback: onSubmit,
size: 'invisible'
});
</script>
Aucun widget visible. reCAPTCHA s'active lorsque l'utilisateur déclenche l'élément spécifié ou lorsque grecaptcha.execute() est appelé.
Comment détecter quelle variante se trouve sur une page
Détection Python :
import requests
from bs4 import BeautifulSoup
import re
def detect_recaptcha_variant(url):
resp = requests.get(url)
soup = BeautifulSoup(resp.text, "html.parser")
# Check for invisible indicators
invisible_widget = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
if invisible_widget:
return {
"variant": "invisible",
"sitekey": invisible_widget.get("data-sitekey"),
"callback": invisible_widget.get("data-callback")
}
# Check for programmatic invisible in scripts
for script in soup.find_all("script"):
if script.string and "invisible" in str(script.string):
key_match = re.search(r"sitekey['\"]?\s*[:=]\s*['\"]([^'\"]+)", script.string)
if key_match:
return {
"variant": "invisible-programmatic",
"sitekey": key_match.group(1),
"callback": "check grecaptcha.render() call"
}
# Check for standard checkbox
checkbox_widget = soup.find(class_="g-recaptcha")
if checkbox_widget:
return {
"variant": "checkbox",
"sitekey": checkbox_widget.get("data-sitekey"),
"callback": checkbox_widget.get("data-callback")
}
return None
result = detect_recaptcha_variant("https://example.com/login")
print(result)
Détection Node.js :
const axios = require("axios");
const cheerio = require("cheerio");
async function detectRecaptchaVariant(url) {
const { data } = await axios.get(url);
const $ = cheerio.load(data);
// Check for invisible
const invisible = $(".g-recaptcha[data-size='invisible']");
if (invisible.length) {
return {
variant: "invisible",
sitekey: invisible.attr("data-sitekey"),
callback: invisible.attr("data-callback"),
};
}
// Check scripts for programmatic invisible
const scripts = $("script")
.map((_, el) => $(el).html())
.get()
.join("\n");
if (scripts.includes("invisible")) {
const keyMatch = scripts.match(/sitekey['"]?\s*[:=]\s*['"]([^'"]+)/);
if (keyMatch) {
return {
variant: "invisible-programmatic",
sitekey: keyMatch[1],
callback: "check render call",
};
}
}
// Check for standard checkbox
const checkbox = $(".g-recaptcha");
if (checkbox.length) {
return {
variant: "checkbox",
sitekey: checkbox.attr("data-sitekey"),
callback: checkbox.attr("data-callback"),
};
}
return null;
}
Vérification rapide de la console du navigateur :
const el = document.querySelector('[data-size="invisible"]');
console.log(el ? "Invisible reCAPTCHA" : "Checkbox reCAPTCHA");
| Signal de détection | v2 Case à cocher | v2 invisible |
|---|---|---|
data-size="invisible" |
Pas présent | Présent |
| Case à cocher visible sur la page | Oui | Non |
grecaptcha.execute() a appelé |
Non (l'utilisateur clique) | Oui (programmatique) |
| Position contextuelle du défi | En ligne, case à cocher ci-dessous | Coin inférieur droit de la page |
Résolution avec CaptchaAI
v2 Case à cocher
import requests
import time
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": "6Le-wvkSAAAA...",
"pageurl": "https://example.com/form"
})
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY", "action": "get", "id": task_id
})
if result.text.startswith("OK|"):
token = result.text.split("|")[1]
break
v2 invisible
import requests
import time
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": "6Le-wvkSAAAA...",
"pageurl": "https://example.com/form",
"invisible": 1 # Only parameter difference
})
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY", "action": "get", "id": task_id
})
if result.text.startswith("OK|"):
token = result.text.split("|")[1]
break
Injection de jetons – la différence critique
Case à cocher v2 : Le champ masqué est généralement suffisant
# Selenium — inject into hidden field
driver.execute_script(
f'document.getElementById("g-recaptcha-response").value = "{token}";'
)
# If the page uses a callback, also call it
callback = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
if callback:
driver.execute_script(f'{callback}("{token}");')
v2 Invisible : le rappel est presque toujours requis
# Selenium — inject AND call the callback
driver.execute_script(
f'document.getElementById("g-recaptcha-response").value = "{token}";'
)
# CRITICAL: Invisible reCAPTCHA almost always requires calling the callback
callback_name = driver.find_element(
"css selector", ".g-recaptcha[data-size='invisible']"
).get_attribute("data-callback")
driver.execute_script(f'{callback_name}("{token}");')
// Puppeteer — invisible callback injection
await page.evaluate((tok) => {
// Set the hidden field
document.getElementById("g-recaptcha-response").value = tok;
// Find and call the callback function
const widget = document.querySelector("[data-size='invisible']");
const cbName = widget?.getAttribute("data-callback");
if (cbName && typeof window[cbName] === "function") {
window[cbName](tok);
}
}, token);
Différence clé : Les formulaires de case à cocher v2 fonctionnent souvent avec uniquement l'injection de champ caché, car le clic de l'utilisateur sur la case à cocher a déjà enregistré le rappel. Invisible reCAPTCHA n'a jamais ce clic : le rappel doit être appelé explicitement.
Solveur universel pour les deux variantes
import requests
import time
from bs4 import BeautifulSoup
class RecaptchaV2UniversalSolver:
def __init__(self, api_key):
self.api_key = api_key
def detect_and_solve(self, page_url, page_html=None):
if not page_html:
page_html = requests.get(page_url).text
soup = BeautifulSoup(page_html, "html.parser")
# Detect variant
invisible = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
widget = invisible or soup.find(class_="g-recaptcha")
if not widget:
raise Exception("No reCAPTCHA widget found")
sitekey = widget.get("data-sitekey")
is_invisible = invisible is not None
callback = widget.get("data-callback")
params = {
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url
}
if is_invisible:
params["invisible"] = 1
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
if not resp.text.startswith("OK|"):
raise Exception(f"Submit failed: {resp.text}")
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key, "action": "get", "id": task_id
})
if result.text.startswith("OK|"):
return {
"token": result.text.split("|")[1],
"variant": "invisible" if is_invisible else "checkbox",
"callback": callback,
"sitekey": sitekey
}
if result.text != "CAPCHA_NOT_READY":
raise Exception(f"Solve error: {result.text}")
raise Exception("Timed out")
# Usage
solver = RecaptchaV2UniversalSolver("YOUR_API_KEY")
result = solver.detect_and_solve("https://example.com/login")
print(f"Variant: {result['variant']}, Callback: {result['callback']}")
Dépannage
| Problème | Correction de la case à cocher | Solution invisible |
|---|---|---|
| Jeton non accepté | Injecter dans le champ g-recaptcha-response |
Injecter ET appeler la fonction data-callback |
| Widget introuvable | Recherchez la classe .g-recaptcha |
Recherchez data-size="invisible" ou les appels de rendu de script |
| Le formulaire est soumis mais échoue | Vérifiez si un rappel est attendu | Un rappel est presque toujours nécessaire : trouvez-le et appelez-le |
| Rechargement de la page après injection | La validation JavaScript a échoué | Rappel d'appel avant les déclencheurs de soumission automatique du formulaire |
FAQ
Le reCAPTCHA invisible est-il plus difficile à résoudre ?
Non. Le processus de résolution via CaptchaAI est presque identique. L'ajout de invisible=1 à votre demande est le seul changement. Le défi supplémentaire se situe du côté de l’injection : vous devez trouver et exécuter la fonction de rappel.
Les deux utilisent-ils le même format de clé de site ?
Oui. Le format de la clé de site est identique. Vous ne pouvez pas distinguer la variante à partir de la clé du site uniquement – recherchez data-size="invisible" dans le code HTML.
Le reCAPTCHA invisible affiche-t-il toujours des problèmes d'image ?
Oui. Lorsque Google détecte un comportement suspect, invisible reCAPTCHA affiche une fenêtre contextuelle de défi d'image dans le coin inférieur droit de la page. C'est pourquoi vous avez toujours besoin de CaptchaAI : la version invisible peut toujours présenter des défis.
Un site peut-il basculer entre case à cocher et invisible ?
Oui. Il s'agit d'un changement de configuration du côté du site : même clé de site, implémentation différente. Certains sites utilisent une case à cocher sur ordinateur et invisible sur mobile. Détectez toujours la variante de manière dynamique.
Qu’est-ce qui est le plus rapide à résoudre ?
Les résolutions invisibles sont généralement légèrement plus rapides (10 à 25 secondes contre 10 à 30 secondes) car elles ont tendance à déclencher moins de défis d'image. Mais la différence est marginale.
Guides associés
- Comment résoudre reCAPTCHA v2 à l'aide de l'API— tutoriel complet sur les cases à cocher v2
- Comment fonctionne reCAPTCHA Invisible— mécanisme invisible expliqué
- Comment résoudre reCAPTCHA Invisible à l'aide de l'API— tutoriel de résolution invisible
- Erreurs et correctifs courants de reCAPTCHA Invisible— dépannage invisible
- Comment résoudre reCAPTCHA Invisible à l'aide de l'API
- Comment fonctionne reCAPTCHA Invisible
- reCAPTCHA v2 vs v3 expliqué