Comparisons

Guide de résolution Standard vs Enterprise reCAPTCHA v3

Un seul paramètre sépare les deux intégrations : enterprise=1. Si la page charge enterprise.js, vous l'ajoutez à votre requête vers l'API CaptchaAI ; si elle charge api.js?render=, vous l'omettez. Le reste est identique : même sitekey, même paramètre action, même polling sur res.php, même injection dans g-recaptcha-response.

La difficulté est ailleurs : les deux variantes sont invisibles, et rien ne les distingue à l'écran. Une équipe qui code en dur la mauvaise variante ne le découvre qu'au moment où le taux de réussite de son pipeline chute, sans erreur explicite.

Ce que le drapeau enterprise=1 change vraiment

Enterprise n'est pas une v4 : c'est le même score de risque (0,0 à 1,0) livré dans l'écosystème Google Cloud, avec codes de motif, seuils par action et Account Defender. Ces fonctions concernent le site qui vérifie le token, pas le client qui le produit.

Côté résolution, seuls trois éléments changent :

  • le fichier JS chargé ;
  • la fonction appelée (grecaptcha.enterprise.execute()) ;
  • le drapeau enterprise=1.

Différences entre reCAPTCHA v3 standard et Enterprise

Les chiffres ci-dessous reposent sur des mesures observées et des retours d'utilisateurs ; les résultats varient selon l'environnement, le volume et le moment de la journée.

Caractéristique v3 standard v3 Enterprise
Fonctionnement invisible Oui Oui
Score (0,0 à 1,0) Oui Oui
Paramètre action Obligatoire Obligatoire
Fichier JS api.js?render=KEY enterprise.js?render=KEY
Fonction d'exécution grecaptcha.execute() grecaptcha.enterprise.execute()
Codes de motif Non Oui (AUTOMATION, TOO_MUCH_TRAFFIC…)
Seuils par action Non Oui (via Cloud Console)
Détection de fuite de mot de passe Non Oui
Account Defender Non Oui
Endpoint de vérification siteverify (gratuit) recaptchaenterprise.googleapis.com (payant)
Paramètres CaptchaAI version=v3 version=v3 + enterprise=1
Temps de résolution typique 10–20 s 10–20 s

Repérer la version chargée par une page

Sans widget visible, la détection passe par le HTML et le JavaScript de la page.

En Python :

import requests
import re

def detect_v3_type(url):
    resp = requests.get(url)
    html = resp.text

    # Check for enterprise.js
    if "enterprise.js" in html:
        version = "enterprise_v3"
        execute_fn = "grecaptcha.enterprise.execute"
    elif "recaptcha/api.js" in html and "render=" in html:
        version = "standard_v3"
        execute_fn = "grecaptcha.execute"
    else:
        return None

    # Extract sitekey from render parameter
    key_match = re.search(r'render[=:]\s*["\']?([A-Za-z0-9_-]{40})', html)
    sitekey = key_match.group(1) if key_match else None

    # Extract action parameter
    action_match = re.search(r'action["\']?\s*[:=]\s*["\'](\w+)', html)
    action = action_match.group(1) if action_match else "unknown"

    return {
        "version": version,
        "sitekey": sitekey,
        "action": action,
        "execute_fn": execute_fn
    }

info = detect_v3_type("https://example.com/login")
print(info)

En Node.js :

const axios = require("axios");

async function detectV3Type(url) {
  const { data: html } = await axios.get(url);

  let version, executeFn;
  if (html.includes("enterprise.js")) {
    version = "enterprise_v3";
    executeFn = "grecaptcha.enterprise.execute";
  } else if (html.includes("recaptcha/api.js") && html.includes("render=")) {
    version = "standard_v3";
    executeFn = "grecaptcha.execute";
  } else {
    return null;
  }

  const keyMatch = html.match(/render[=:]\s*['"]?([A-Za-z0-9_-]{40})/);
  const actionMatch = html.match(/action['"]?\s*[:=]\s*['"](\w+)/);

  return {
    version,
    sitekey: keyMatch?.[1] || null,
    action: actionMatch?.[1] || "unknown",
    executeFn,
  };
}

Contrôle rapide dans la console du navigateur :

// Paste in DevTools console
if (document.querySelector('script[src*="enterprise.js"]')) {
  console.log("Enterprise v3");
  console.log("Execute:", typeof grecaptcha?.enterprise?.execute);
} else if (document.querySelector('script[src*="api.js"][src*="render="]')) {
  console.log("Standard v3");
  console.log("Execute:", typeof grecaptcha?.execute);
}

Un réflexe utile : ne gardez pas le HTML complet des pages auditées dans vos logs. Il contient souvent des identifiants de session, et cette minimisation limite la collecte de données personnelles au regard du RGPD.

Résoudre les deux versions avec l'API CaptchaAI

v3 standard

Soumettez la tâche sur in.php avec method=userrecaptcha, version=v3, la sitekey et l'action, puis interrogez res.php.

import requests
import time

# Submit
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "version": "v3",
    "googlekey": sitekey,
    "action": "login",
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

# Poll
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

v3 Enterprise

Même requête, plus enterprise=1. L'interrogation du résultat est strictement identique : inutile de dupliquer votre couche de polling.

import requests
import time

# Submit — add enterprise=1
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "version": "v3",
    "enterprise": 1,  # Required for Enterprise
    "googlekey": sitekey,
    "action": "login",
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

# Polling is identical to standard
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

Détection et résolution dans une seule classe

En production, la détection ne doit pas rester manuelle. Cette classe lit la page, choisit la variante, extrait la sitekey et l'action, puis résout : une migration vers Enterprise devient transparente.

import requests
import time
import re

class RecaptchaV3Solver:
    def __init__(self, api_key):
        self.api_key = api_key

    def detect_and_solve(self, page_url, action=None):
        """Auto-detect standard vs enterprise and solve."""
        html = requests.get(page_url).text

        is_enterprise = "enterprise.js" in html
        key_match = re.search(r'render[=:]\s*["\']?([A-Za-z0-9_-]{40})', html)
        if not key_match:
            raise Exception("No v3 sitekey found")
        sitekey = key_match.group(1)

        if not action:
            action_match = re.search(r'action["\']?\s*[:=]\s*["\'](\w+)', html)
            action = action_match.group(1) if action_match else "verify"

        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "version": "v3",
            "googlekey": sitekey,
            "action": action,
            "pageurl": page_url
        }
        if is_enterprise:
            params["enterprise"] = 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 result.text.split("|")[1]
            if result.text != "CAPCHA_NOT_READY":
                raise Exception(f"Solve failed: {result.text}")

        raise Exception("Timed out")

solver = RecaptchaV3Solver("YOUR_API_KEY")
token = solver.detect_and_solve("https://example.com/login", action="login")
print(f"Token: {token[:40]}...")

Extraire le paramètre action avant de soumettre

L'action pèse directement sur le score. Une valeur devinée (verify sur un formulaire qui déclare login) produit un score bas et un token refusé, sans erreur côté API. Extrayez la chaîne exacte du JavaScript.

import re

def find_v3_actions(html):
    """Extract all action parameters from page JavaScript."""
    # Look for grecaptcha.execute(key, {action: '...'})
    pattern = r"(?:grecaptcha\.(?:enterprise\.)?execute|action)\s*[(:]\s*['\"](\w+)"
    actions = re.findall(pattern, html)
    return list(set(actions))

# Common actions: "login", "submit", "register", "checkout", "homepage"

Erreurs de paramétrage qui font rejeter un token

Erreur Résultat Correctif
enterprise=1 envoyé sur du v3 standard Token potentiellement invalide Vérifier enterprise.js avant d'ajouter le drapeau
enterprise=1 oublié sur du v3 Enterprise Token rejeté par le backend L'ajouter dès que enterprise.js est présent
Mauvais paramètre action Score bas, token rejeté Extraire la chaîne exacte du JavaScript de la page
version=v3 omis Tâche traitée comme du v2 Toujours envoyer version=v3 pour le reCAPTCHA à score
Sitekey v2 utilisée en v3 ERROR_WRONG_GOOGLEKEY Les sitekeys v3 viennent de render=KEY

Injecter le token dans le formulaire

L'injection ne dépend pas de la variante : le champ cible reste g-recaptcha-response.

# For browser-based workflows (Selenium)
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# For pure HTTP workflows
requests.post(page_url, data={
    "g-recaptcha-response": token,
    "username": "user",
    "password": "pass"
})
// Puppeteer
await page.evaluate((tok) => {
  document.getElementById("g-recaptcha-response").value = tok;
}, token);

// Pure HTTP (axios)
await axios.post(pageUrl, new URLSearchParams({
  "g-recaptcha-response": token,
  username: "user",
  password: "pass",
}));

Volume, threads et budget

CaptchaAI facture des threads simultanés, pas des résolutions : un thread est une résolution en vol, avec des résolutions illimitées par thread. Le v3 Enterprise ne coûte donc pas plus cher que le standard ; c'est votre parallélisme qui détermine le plan.

Exemple : une équipe QA française lance chaque nuit une campagne Playwright depuis une instance Scaleway à Paris, avec 8 parcours de connexion en parallèle sur une recette protégée par v3 Enterprise. Ces 8 résolutions simultanées tiennent dans STANDARD ($30/mois, 15 threads) ; à 40 scénarios parallèles, ADVANCE ($90/mois, 50 threads) absorbe la charge sans changer une ligne de code. Le plan d'entrée reste BASIC ($15/mois, 5 threads).

FAQ

Faut-il un compte Google Cloud pour résoudre du reCAPTCHA v3 Enterprise ?

Non. Le projet Google Cloud et l'endpoint recaptchaenterprise.googleapis.com concernent le site qui vérifie le token ; côté client, la sitekey publique, l'action et votre clé API suffisent à résoudre.

Comment détecter Enterprise v3 par programmation ?

Cherchez enterprise.js dans la source de la page ; avec un navigateur piloté, la source complète suffit :

page_source = driver.page_source
is_enterprise = "enterprise.js" in page_source

Le token est accepté mais le score reste bas : que vérifier ?

L'action d'abord : elle doit correspondre exactement à celle déclarée par la page. Vérifiez ensuite la cohérence de la session : même IP, mêmes en-têtes, même enchaînement jusqu'à l'envoi du formulaire.

CaptchaAI prend-il en charge hCaptcha si le site bascule ?

Non — hCaptcha n'est pas pris en charge, pas plus que FunCaptcha (Arkose Labs) : un site qui bascule sort du périmètre couvert. GeeTest v4 est à venir ; GeeTest v3, Cloudflare Turnstile et Cloudflare Challenge sont pris en charge.

Combien de threads prévoir pour une campagne nocturne ?

Comptez un thread par résolution simultanée, jamais par test. Si la file d'attente s'allonge, augmentez les threads.

Guides associés

Les commentaires sont désactivés pour cet article.