Explainers

Solve Media CAPTCHA : ce que c'est et comment le résoudre

Solve Media est un CAPTCHA texte qui demande de recopier un slogan publicitaire — « Taste The Rainbow » au lieu de « aX3kP ». Pour votre code, cela change peu de chose : la phrase est affichée sous forme d'image, donc elle se traite comme n'importe quel CAPTCHA image/OCR, en envoyant la capture à l'API et en saisissant le texte renvoyé.

Ce qui change, c'est la nature du texte. Solve Media était un produit publicitaire avant d'être un produit de sécurité : la phrase devait rester parfaitement lisible pour que le message de marque passe. Le service appartient aujourd'hui à Permit.io / Radius Networks et les nouveaux déploiements sont rares, mais le widget survit sur des formulaires anciens que vous croiserez encore en automatisation ou en recette.


Le parcours de vérification, étape par étape

  1. Le widget se charge et affiche un message publicitaire sous forme d'image
  2. L'utilisateur lit la phrase de marque et la saisit dans le champ prévu
  3. La réponse est vérifiée par les serveurs de Solve Media
  4. Si elle est correcte, la soumission du formulaire se poursuit
┌─────────────────────────────────┐
│                                 │
│   "Taste The Rainbow"           │
│                                 │
├─────────────────────────────────┤
│ Type the phrase: [____________] │
│                     [Verify]    │
└─────────────────────────────────┘

Rien n'est signé, rien n'est scoré : la vérification porte uniquement sur la chaîne saisie. C'est ce qui rend le type simple à automatiser une fois la phrase lue.


Reconnaître Solve Media dans le DOM

Avant d'écrire la moindre ligne de résolution, confirmez le type de défi CAPTCHA. Solve Media laisse des marqueurs très reconnaissables dans le HTML :

<!-- Solve Media script -->
<script src="https://api.solvemedia.com/papi/challenge.script"></script>

<!-- Widget container -->
<div id="adcopy-outer"></div>

<!-- Hidden response fields -->
<input type="hidden" name="adcopy_challenge" />
<input type="hidden" name="adcopy_response" />

Retenez la règle simple : tout élément dont l'id ou le name commence par adcopy- ou contient solvemedia signale Solve Media. Côté champs cachés, adcopy_challenge porte l'identifiant du défi et adcopy_response reçoit la phrase saisie.


Pourquoi Solve Media se lit mieux qu'un CAPTCHA texte classique

Caractéristique Solve Media CAPTCHA texte classique
Contenu du texte Slogans de marque, mots anglais Caractères aléatoires
Lisibilité Élevée (pensée pour être lue) Faible (pensée pour résister)
Distorsion Minime Forte
Modèle économique Publicité Aucun
Difficulté pour l'OCR Faible (texte propre) Élevée (glyphes déformés)
Expérience utilisateur Meilleure (mots reconnaissables) Moins bonne (déchiffrage)

Conséquence pratique : un pipeline OCR déjà en place pour les CAPTCHA image absorbe Solve Media sans nouvelle intégration. Il n'y a ni sitekey à extraire, ni token à réinjecter dans un champ dédié comme avec reCAPTCHA v2 — juste une chaîne de caractères à taper.


Résoudre Solve Media avec l'API CaptchaAI

Comme la phrase est rendue en image, la méthode OCR standard suffit : capturez le widget, envoyez l'image en base64 à in.php, puis interrogez res.php jusqu'à obtenir le texte.

Python

import requests
import time
import base64

API_KEY = "YOUR_API_KEY"

# Capture the CAPTCHA image
# Method 1: Screenshot the widget
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com/page-with-solvemedia")

captcha_img = driver.find_element(By.CSS_SELECTOR, "#adcopy-puzzle-image img")
captcha_img.screenshot("solvemedia.png")

# Submit to CaptchaAI
with open("solvemedia.png", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode()

response = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "base64",
    "body": img_b64,
    "phrase": 1,      # Contains spaces (multi-word phrase)
    "json": 1
})

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

# Poll for solution
for _ in range(30):
    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:
        text = result["request"]
        print(f"Phrase: {text}")
        break

# Type the phrase
driver.find_element(By.CSS_SELECTOR, "#adcopy_response").send_keys(text)
driver.find_element(By.CSS_SELECTOR, "form").submit()

Node.js

const axios = require('axios');
const fs = require('fs');

async function solveSolveMedia(imagePath) {
  const imageB64 = fs.readFileSync(imagePath).toString('base64');

  const submit = await axios.post('https://ocr.captchaai.com/in.php', null, {
    params: {
      key: 'YOUR_API_KEY',
      method: 'base64',
      body: imageB64,
      phrase: 1,
      json: 1
    }
  });

  const taskId = submit.data.request;

  for (let i = 0; i < 30; i++) {
    await new Promise(r => setTimeout(r, 5000));
    const res = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: 'YOUR_API_KEY', action: 'get', id: taskId, json: 1 }
    });
    if (res.data.status === 1) return res.data.request;
  }
  throw new Error('Timeout');
}

Paramètres OCR à régler

Paramètre Pourquoi
phrase=1 Les slogans Solve Media contiennent des espaces
numeric=2 Les phrases sont presque toujours composées de lettres seules
Pas de min_len/max_len La longueur du slogan varie d'une campagne à l'autre
Casse conservée telle quelle Certaines implémentations ne sont pas sensibles à la casse

Côté polling, gardez l'intervalle de 5 s et le plafond de tentatives des exemples ci-dessus : interroger res.php chaque seconde n'accélère rien et consomme votre quota.


Scénario : reprendre un formulaire hérité chez un client francophone

Le cas le plus fréquent n'est pas un nouveau site, c'est une migration. Une équipe QA reprend un extranet fournisseur déployé vers 2014 chez un client belge : le formulaire de demande d'accès est toujours protégé par Solve Media, et la suite de tests Selenium qui tourne sur un worker OVHcloud échoue à chaque exécution nocturne.

La reprise tient en trois décisions :

  • Détection avant résolution. Le script teste la présence de #adcopy-outer ; sinon, il bascule sur le traitement reCAPTCHA v2 déjà en place. Un même parc mélange souvent les deux générations.
  • Latence assumée. Si vos workers tournent en eu-west-3 (Paris) ou chez Scaleway, la résolution OCR reste largement dominée par le temps de traitement, pas par le réseau. Dimensionnez vos timeouts sur le temps de résolution observé, pas sur un aller-retour HTTP.
  • RGPD. Une capture de formulaire peut contenir des données saisies par un utilisateur. Ne conservez que l'image du défi CAPTCHA, purgez-la après résolution et vérifiez vos obligations RGPD avant d'en journaliser davantage.

Combien de threads prévoir

La facturation CaptchaAI se fait au thread simultané, pas à la résolution : un thread traite un CAPTCHA en vol, puis enchaîne. Dimensionnez sur votre parallélisme réel, pas sur le volume total.

  • Suite de recette nocturne, quelques dizaines de formulaires : BASIC ($15/mois, 5 threads).
  • Parc de formulaires hérités testés en parallèle : STANDARD ($30/mois, 15 threads).
  • Crawler de conformité sur plusieurs centaines de pages : ADVANCE ($90/mois, 50 threads).

La facturation est en dollars US.


Dépannage

Problème Cause probable Correctif
L'OCR renvoie un seul mot phrase=1 absent de la requête Ajoutez phrase=1 pour autoriser les espaces
Réponse refusée malgré un texte correct Le défi a expiré pendant le polling Rechargez le widget et relancez la résolution
Image capturée vide ou noire Capture déclenchée avant le rendu du widget Attendez la présence de #adcopy-puzzle-image img
Chiffres parasites dans la phrase numeric non contraint Envoyez numeric=2 pour privilégier les lettres
Le formulaire ne part pas Phrase écrite dans le mauvais champ Ciblez #adcopy_response, jamais adcopy_challenge

FAQ

Solve Media est-il encore déployé aujourd'hui ?

Rarement. Le service a été racheté puis rebaptisé, et les intégrations restantes sont des vestiges sur des sites anciens. Prévoyez donc une détection conditionnelle plutôt qu'un traitement systématique.

Faut-il une méthode API dédiée pour Solve Media ?

Non. La méthode OCR image standard (method=base64 ou method=post) avec phrase=1 couvre le cas. Aucun paramètre spécifique au fournisseur n'est nécessaire.

CaptchaAI prend-il en charge hCaptcha ou FunCaptcha ?

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

Que faire si la phrase renvoyée est tronquée ?

Deux causes dominent :

  • Un rognage trop serré sur #adcopy-puzzle-image, qui coupe le dernier mot de la capture.
  • Une contrainte de longueur envoyée à l'API : retirez min_len/max_len, les slogans font de deux à cinq mots selon la campagne.

Puis-je réutiliser une phrase déjà résolue ?

Non. Chaque adcopy_challenge est lié à une session et expire côté serveur. Résolvez à la demande, gérez l'expiration avec un retry, et repartez d'un widget rechargé plutôt que d'une valeur mise en cache.


Guides associés

Pour approfondir la chaîne OCR de bout en bout :

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