Explainers

L'API Assessment de reCAPTCHA Enterprise : scores et raisons

Côté navigateur, reCAPTCHA Enterprise ne demande rien de plus que reCAPTCHA v3 : le même appel execute(), le même token opaque. Toute la différence se joue côté serveur, dans l'API Assessment, qui renvoie le score, les raisons chiffrées derrière ce score et un verdict sur le compte utilisateur. Pour une équipe d'automatisation, la conséquence tient en une ligne : un seul paramètre change dans la requête envoyée au solveur.

Le trajet complet d'une évaluation Enterprise

Le flux se lit en deux moitiés, séparées par l'envoi du token à votre backend :

Client-side:

  1. Load reCAPTCHA Enterprise script
  2. Call grecaptcha.enterprise.execute(SITE_KEY, {action: 'LOGIN'})
  3. Receive token
  4. Send token to your backend

Server-side:

  1. Create assessment via Enterprise API
  2. Receive detailed risk analysis
  3. Make access decision based on score + reasons
  4. Optionally annotate the assessment (report fraud/legitimate)

L'étape 4 est propre à Enterprise : l'exploitant réinjecte le verdict humain (fraude avérée, client légitime) pour affiner le modèle sur son trafic.

Enterprise ou reCAPTCHA v3 : ce qui change vraiment

Caractéristique reCAPTCHA v3 (gratuit) reCAPTCHA Enterprise
Score 0,0 à 1,0 0,0 à 1,0 + raisons
Analyse de risque Basique Détaillée (fraude, données de compte)
Raisons du score Absentes Explicites, derrière chaque score
Account Defender Non Oui (suivi du cycle de vie du compte)
Intégration WAF Non Oui (Cloudflare, Fastly, F5)
Express Non Oui (côté serveur uniquement, sans JS)
Détection de fuite de mot de passe Non Oui
Tarif Gratuit (1 million d'évaluations/mois) $1 pour 1 000 évaluations (1 million gratuit)
Endpoint API google.com/recaptcha/api/siteverify recaptchaenterprise.googleapis.com

Retenez la dernière ligne : la validation ne passe plus par siteverify. Un backend migré vers Enterprise mais resté sur l'ancien endpoint renvoie des erreurs alors que le token, lui, est valide.

Poser le SDK côté client

Le script Enterprise

<script src="https://www.google.com/recaptcha/enterprise.js?render=SITE_KEY"></script>
<script>
    grecaptcha.enterprise.ready(function() {
        grecaptcha.enterprise.execute('SITE_KEY', { action: 'LOGIN' })
            .then(function(token) {
                // Send token to backend
                fetch('/api/verify', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ token: token })
                });
            });
    });
</script>

Trois écarts seulement par rapport à reCAPTCHA v3 :

  • Le script chargé est .../recaptcha/enterprise.js et non .../recaptcha/api.js
  • L'objet exposé est grecaptcha.enterprise et non grecaptcha
  • execute() produit un token au format identique

Repérer Enterprise dans le code source d'une page

Première chose à automatiser quand vous auditez un parc de sites :

import requests
import re

def detect_recaptcha_enterprise(url):
    """Detect if a page uses reCAPTCHA Enterprise."""
    html = requests.get(url, timeout=10).text

    indicators = {
        "is_enterprise": False,
        "is_standard": False,
        "site_key": None,
        "actions": [],
    }

    # Enterprise detection
    if "recaptcha/enterprise.js" in html:
        indicators["is_enterprise"] = True
        match = re.search(r"render=([A-Za-z0-9_-]+)", html)
        if match:
            indicators["site_key"] = match.group(1)

    # Standard v3 detection
    elif "recaptcha/api.js?render=" in html:
        indicators["is_standard"] = True
        match = re.search(r"render=([A-Za-z0-9_-]+)", html)
        if match:
            indicators["site_key"] = match.group(1)

    # Extract action names
    actions = re.findall(r"action:\s*['\"](\w+)['\"]", html)
    indicators["actions"] = list(set(actions))

    return indicators

print(detect_recaptcha_enterprise("https://example.com/login"))

Le champ actions collecte les noms d'action utilisés par la page (LOGIN, CHECKOUT, SIGNUP…) : transmettez-les à l'identique au solveur.

Créer une évaluation côté serveur

Cette partie concerne l'exploitant du site, pas l'automatisation — mais elle explique pourquoi un token accepté peut quand même aboutir à un blocage.

L'appel via le client Google Cloud

from google.cloud import recaptchaenterprise_v1
from google.cloud.recaptchaenterprise_v1 import Assessment

def create_assessment(project_id, site_key, token, action):
    """Create a reCAPTCHA Enterprise assessment."""
    client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()

    event = recaptchaenterprise_v1.Event()
    event.site_key = site_key
    event.token = token
    event.expected_action = action

    assessment = recaptchaenterprise_v1.Assessment()
    assessment.event = event

    request = recaptchaenterprise_v1.CreateAssessmentRequest()
    request.assessment = assessment
    request.parent = f"projects/{project_id}"

    response = client.create_assessment(request)
    return response

La réponse renvoyée

{
    "name": "projects/123456/assessments/abcdef123",
    "event": {
        "token": "...",
        "siteKey": "6Le...",
        "expectedAction": "LOGIN",
        "hashedAccountId": "abc123..."
    },
    "riskAnalysis": {
        "score": 0.9,
        "reasons": [
            "AUTOMATION",
            "TOO_MUCH_TRAFFIC"
        ],
        "extendedVerdictReasons": [
            "BROWSER_ERROR"
        ]
    },
    "tokenProperties": {
        "valid": true,
        "hostname": "example.com",
        "action": "LOGIN",
        "createTime": "2025-01-15T10:30:00Z",
        "invalidReason": ""
    },
    "accountDefenderAssessment": {
        "labels": ["PROFILE_MATCH"]
    }
}

Deux blocs, dans l'ordre : tokenProperties.valid dit si le token est authentique, riskAnalysis.score dit si la session mérite votre confiance. Un valid: true assorti d'un score de 0,1 est normal, pas un défaut d'intégration.

hashedAccountId mérite une note à part : c'est un identifiant utilisateur transmis à un tiers, même haché. Si vous exploitez le site depuis la France ou la Belgique, inscrivez-le à votre registre de traitements RGPD et réservez-le aux parcours qui en ont besoin (connexion, paiement).

Pourquoi un score s'effondre : les raisons renvoyées

C'est l'apport principal d'Enterprise. Là où v3 laisse deviner, Enterprise nomme le signal :

Raison Ce qu'elle signale Effet sur le score
AUTOMATION User-agent automatisé ou navigateur headless -0,3 à -0,7
UNEXPECTED_ENVIRONMENT Incohérences navigateur ou appareil -0,2 à -0,4
TOO_MUCH_TRAFFIC Volume élevé depuis cette IP ou cette session -0,1 à -0,3
UNEXPECTED_USAGE_PATTERNS Comportement éloigné des normes humaines -0,2 à -0,5
LOW_CONFIDENCE_SCORE Données insuffisantes pour trancher Variable
SUSPECTED_CARDING Schéma proche d'une fraude à la carte -0,3 à -0,6
SUSPECTED_CHARGEBACK Risque d'impayé d'après la transaction -0,2 à -0,4

Ces amplitudes sont indicatives : elles reposent sur des observations de terrain et varient selon le site, le volume et l'heure de la journée.

Les raisons de verdict étendues

Raison Ce qu'elle signale
BROWSER_ERROR Erreurs JavaScript pendant l'exécution du SDK CAPTCHA
SITE_MISMATCH Token émis pour un site différent de celui qui le valide
FAILED_TWO_FACTOR Échec récent d'une authentification à deux facteurs

Account Defender : le verdict sur le compte

Account Defender juge le compte, pas la session :

{
    "accountDefenderAssessment": {
        "labels": [
            "PROFILE_MATCH",
            "SUSPICIOUS_LOGIN_ACTIVITY",
            "SUSPICIOUS_ACCOUNT_CREATION",
            "RELATED_ACCOUNTS_NUMBER_HIGH"
        ]
    }
}
Étiquette Signification
PROFILE_MATCH Le comportement correspond au profil connu du compte
SUSPICIOUS_LOGIN_ACTIVITY Connexion inhabituelle (nouvel appareil, nouvelle localisation)
SUSPICIOUS_ACCOUNT_CREATION La création du compte semble automatisée
RELATED_ACCOUNTS_NUMBER_HIGH Plusieurs comptes rattachés au même appareil ou à la même session

Ces étiquettes restent dans la console de l'exploitant, invisibles depuis l'extérieur.

Enterprise posé à la périphérie : l'intégration WAF

Beaucoup de sites francophones à fort trafic — e-commerce, médias, réservation — branchent Enterprise non pas dans leur code applicatif mais dans leur WAF. Le défi surgit alors avant l'origine, qu'elle soit hébergée chez OVHcloud, Scaleway ou en région AWS eu-west-3.

Chez Cloudflare

Request arrives at Cloudflare edge
    ↓
Cloudflare WAF rule evaluates request
    ↓
Rule triggers reCAPTCHA Enterprise challenge
    ↓
Client solves CAPTCHA → token returned
    ↓
Cloudflare validates token via Enterprise API
    ↓
If valid + score above threshold → request forwarded to origin

Chez F5 BIG-IP

F5 iRule or policy evaluates request
    ↓
Triggers reCAPTCHA Enterprise challenge page
    ↓
Client solves → token validated server-side
    ↓
F5 forwards or blocks based on assessment score

Conséquence pour vos tests : un défi peut apparaître sur une URL qui n'affichait aucun formulaire la veille, parce qu'une règle WAF a changé. Détectez à chaque exécution, pas une fois pour toutes.

Traiter Enterprise dans vos automatisations

Un seul paramètre à ajouter

Du point de vue du solveur, un token Enterprise se produit comme un token reCAPTCHA classique : ni endpoint dédié ni méthode spécifique, le paramètre enterprise suffit. La facturation ne bouge pas non plus — CaptchaAI facture au thread simultané, pas à la résolution, dès BASIC ($15/mois, 5 threads).

import requests
import time

API_KEY = "YOUR_API_KEY"

# Enterprise is solved with the same method
# The solver handles the Enterprise variant automatically
submit = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": "6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp",
    "pageurl": "https://enterprise-site.com/login",
    "enterprise": 1,  # Flag for Enterprise variant
    "json": 1,
})

task_id = submit.json()["request"]

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"Enterprise token: {token[:50]}...")
        break

Le token obtenu s'injecte ensuite comme d'habitude dans le champ g-recaptcha-response avant l'envoi du formulaire.

La même chose en Node.js

const axios = require("axios");

async function solveEnterprise(sitekey, pageurl) {
    const API_KEY = "YOUR_API_KEY";

    const { data: submit } = await axios.post(
        "https://ocr.captchaai.com/in.php",
        new URLSearchParams({
            key: API_KEY,
            method: "userrecaptcha",
            googlekey: sitekey,
            pageurl: pageurl,
            enterprise: 1,
            json: 1,
        })
    );

    const taskId = submit.request;

    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");
}

Router automatiquement selon la variante détectée

def identify_recaptcha_version(html):
    """Determine which reCAPTCHA version a page uses."""
    if "recaptcha/enterprise.js" in html:
        return "enterprise"
    elif "recaptcha/api.js?render=" in html:
        return "v3"
    elif "g-recaptcha" in html and 'data-size="invisible"' in html:
        return "v2_invisible"
    elif "g-recaptcha" in html:
        return "v2"
    else:
        return "none"

Branchez-la en amont de l'appel au solveur : elle décide seule d'envoyer enterprise: 1 ou non.

Dépannage

Problème Cause probable Correctif
Token refusé par l'API Enterprise Requête sans indicateur Enterprise Ajoutez enterprise=1
Score bloqué à 0,1 avec un token valide action différente de celle de la page Alignez action sur la valeur du site
SITE_MISMATCH dans les raisons Token généré pour un autre domaine Vérifiez pageurl
AUTOMATION dans les raisons du score Signaux d'environnement côté client Vérifiez votre environnement ; sinon, contactez le support
Token accepté, accès refusé D'autres contrôles se superposent au CAPTCHA Cherchez règles WAF, empreinte de navigateur, limitation de débit

Questions fréquentes

Le paramètre enterprise=1 est-il vraiment obligatoire ?

Oui, dès que la page charge recaptcha/enterprise.js. Sans lui, la requête est traitée comme du reCAPTCHA v3 classique et le token, rendu sans erreur apparente, sera rejeté à la validation.

Résoudre un CAPTCHA Enterprise coûte-t-il plus cher ?

Non. CaptchaAI facture des threads simultanés, sans supplément par type de CAPTCHA : votre débit dépend de votre plan, pas de la variante rencontrée. Le tarif de $1 pour 1 000 évaluations cité plus haut est celui que Google facture à l'exploitant du site.

Comment savoir quelle valeur d'action transmettre ?

Extrayez-la du code source : c'est la chaîne passée à grecaptcha.enterprise.execute(), souvent LOGIN, SIGNUP ou CHECKOUT. La fonction detect_recaptcha_enterprise() ci-dessus la collecte dans son champ actions.

Que faire des données personnelles vues par Enterprise côté RGPD ?

Si vous exploitez le site, traitez hashedAccountId et les étiquettes Account Defender comme des données personnelles : base légale, durée de conservation, mention dans votre politique de confidentialité. Ce n'est pas un avis juridique — référez-vous aux recommandations de la CNIL.

CaptchaAI prend-il en charge hCaptcha ou FunCaptcha comme alternatives ?

Non — ces deux types ne sont pas pris en charge. Les types disponibles sont reCAPTCHA v2 et v3 (Enterprise inclus), Cloudflare Turnstile, Cloudflare Challenge, GeeTest v3 et les CAPTCHA image/OCR. CaptchaFox (bêta), Friendly Captcha (bêta) et Lemin (bêta) sont en phase bêta ; GeeTest v4 est annoncé comme à venir.

À retenir

Enterprise ajoute à reCAPTCHA v3 une analyse de risque explicable, Account Defender et une intégration WAF — trois briques qui servent surtout l'exploitant du site. Pour vos scripts, l'écart tient à deux gestes : détecter recaptcha/enterprise.js, puis transmettre l'indicateur enterprise et la bonne action à votre requête API CaptchaAI. Le reste — polling, injection du token, envoi du formulaire — ne change pas.

Articles connexes

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