Migrer d'AZCaptcha vers CaptchaAI ne demande pas de refonte. Les deux services exposent une API compatible 2Captcha : votre logique d'envoi et d'interrogation du résultat ne bouge pas. Vos workers sur OVHcloud ou Scaleway gardent leur code : changez l'hôte, déplacez la clé, testez en parallèle avant de basculer.
Trois choses seulement changent :
- URL de base :
azcaptcha.com→ocr.captchaai.com(in.phpetres.phpinchangés). - Clé API : générez la vôtre sur captchaai.com, en variable d'environnement.
- Le reste : paramètres, réponse et proxys se transposent tels quels.
Correspondance des endpoints
| Action | AZCaptcha | CaptchaAI |
|---|---|---|
| Envoyer la tâche | https://azcaptcha.com/in.php |
https://ocr.captchaai.com/in.php |
| Récupérer le résultat | https://azcaptcha.com/res.php |
https://ocr.captchaai.com/res.php |
| Vérifier le solde | res.php?action=getbalance |
res.php?action=getbalance |
| Signaler une résolution incorrecte | res.php?action=reportbad |
res.php?action=reportbad |
Paramètres : ce qui reste, ce qui change
La quasi-totalité des paramètres se transposent à l'identique ; seule la clé API diffère :
| Paramètre | AZCaptcha | CaptchaAI | Remarques |
|---|---|---|---|
key |
Clé API | Clé API | Générez la vôtre sur captchaai.com |
method |
userrecaptcha |
userrecaptcha |
Inchangé |
googlekey |
Clé du site | Clé du site | Inchangé |
pageurl |
URL de la page | URL de la page | Inchangé |
json |
1 |
1 |
Inchangé |
proxy |
user:pass@host:port |
user:pass@host:port |
Même format |
proxytype |
HTTP/SOCKS5 |
HTTP/SOCKS5 |
Inchangé |
Étape 1 : récupérez votre clé API CaptchaAI
- Créez un compte sur captchaai.com
- Approvisionnez votre compte
- Copiez votre clé API
Étape 2 : adaptez votre code
Seuls l'URL de base et la clé, désormais en variable d'environnement, changent. Voici l'avant/après :
Python — avant (AZCaptcha)
import requests
API_KEY = "your_azcaptcha_key"
def solve_recaptcha(sitekey, pageurl):
# Submit
resp = requests.post("https://azcaptcha.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data["status"] != 1:
return {"error": data["request"]}
captcha_id = data["request"]
# Poll
import time
for _ in range(60):
time.sleep(5)
result = requests.get("https://azcaptcha.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result["status"] == 1:
return {"solution": result["request"]}
if result["request"] != "CAPCHA_NOT_READY":
return {"error": result["request"]}
return {"error": "TIMEOUT"}
Python — après (CaptchaAI)
import os
import time
import requests
API_KEY = os.environ["CAPTCHAAI_API_KEY"] # Changed: use env var
def solve_recaptcha(sitekey, pageurl):
# Submit — only URL changed
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
# Poll — only URL changed
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
JavaScript — avant (AZCaptcha)
const axios = require("axios");
const API_KEY = "your_azcaptcha_key";
async function solveRecaptcha(sitekey, pageurl) {
const submit = await axios.post("https://azcaptcha.com/in.php", null, {
params: { key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
});
if (submit.data.status !== 1) return { error: submit.data.request };
const captchaId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://azcaptcha.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) return { solution: poll.data.request };
if (poll.data.request !== "CAPCHA_NOT_READY") return { error: poll.data.request };
}
return { error: "TIMEOUT" };
}
JavaScript — après (CaptchaAI)
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY; // Changed: env var
async function solveRecaptcha(sitekey, pageurl) {
// Only URLs changed
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: { key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
});
if (submit.data.status !== 1) return { error: submit.data.request };
const captchaId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) return { solution: poll.data.request };
if (poll.data.request !== "CAPCHA_NOT_READY") return { error: poll.data.request };
}
return { error: "TIMEOUT" };
}
Étape 3 : isolez le fournisseur derrière un wrapper
Encapsulez l'appel dans une classe indépendante du fournisseur : changer de service ne touche plus qu'une ligne.
import os
import time
import requests
class CaptchaProvider:
def __init__(self, base_url, api_key):
self.submit_url = f"{base_url}/in.php"
self.result_url = f"{base_url}/res.php"
self.api_key = api_key
self.session = requests.Session()
def solve(self, sitekey, pageurl, method="userrecaptcha"):
resp = self.session.post(self.submit_url, data={
"key": self.api_key,
"method": method,
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
for _ in range(60):
time.sleep(5)
result = self.session.get(self.result_url, params={
"key": self.api_key, "action": "get",
"id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
# Switch by changing one line:
# provider = CaptchaProvider("https://azcaptcha.com", "old_key")
provider = CaptchaProvider(
"https://ocr.captchaai.com",
os.environ["CAPTCHAAI_API_KEY"]
)
Étape 4 : lancez un test en parallèle
Faites tourner les deux fournisseurs sur le même échantillon pour comparer réussite et temps de résolution avant de trancher :
def parallel_test(sitekey, pageurl, runs=10):
azcaptcha = CaptchaProvider("https://azcaptcha.com", "old_key")
captchaai = CaptchaProvider(
"https://ocr.captchaai.com",
os.environ["CAPTCHAAI_API_KEY"]
)
results = {"azcaptcha": [], "captchaai": []}
for i in range(runs):
start = time.time()
az_result = azcaptcha.solve(sitekey, pageurl)
results["azcaptcha"].append({
"success": "solution" in az_result,
"time": time.time() - start
})
start = time.time()
cai_result = captchaai.solve(sitekey, pageurl)
results["captchaai"].append({
"success": "solution" in cai_result,
"time": time.time() - start
})
for provider, data in results.items():
successes = sum(1 for r in data if r["success"])
avg_time = sum(r["time"] for r in data) / len(data)
print(f"{provider}: {successes}/{runs} success, {avg_time:.1f}s avg")
Dépannage
Les incidents d'une bascule sont rares et se règlent vite :
| Problème | Cause | Correctif |
|---|---|---|
ERROR_KEY_DOES_NOT_EXIST |
Clé API incorrecte | Vérifiez la clé API CaptchaAI dans le tableau de bord |
ERROR_ZERO_BALANCE |
Nouveau compte sans solde | Approvisionnez votre compte sur captchaai.com |
| Codes d'erreur différents | Quelques écarts mineurs entre les deux services | Recensez vos codes d'erreur ; la plupart sont identiques |
| Taux de réussite différent | Pools de résolution distincts | Lancez plus de 50 résolutions de test pour une comparaison statistiquement valable |
Votre check-list de bascule
| Étape | Statut |
|---|---|
| Créer et approvisionner le compte CaptchaAI | ☐ |
| Remplacer l'URL de base partout | ☐ |
| Clé API en variable d'environnement | ☐ |
| Test en parallèle (10 résolutions ou plus) | ☐ |
| Comparer les taux de réussite | ☐ |
| Comparer les temps de résolution | ☐ |
| Adapter supervision et alertes aux endpoints | ☐ |
| Basculer le trafic de production | ☐ |
| Surveiller pendant 24 heures | ☐ |
| Désactiver la clé AZCaptcha | ☐ |
FAQ
Faut-il réécrire toute l'intégration pour migrer ?
Non. Les deux parlent le même format compatible 2Captcha : vous changez l'URL de base et la clé API, les paramètres et le format de réponse restant identiques. Souvent, une recherche-remplacement sur l'URL suffit.
Comment basculer sans risque en production ?
Faites tourner les deux fournisseurs en parallèle avant de couper AZCaptcha. L'étape 4 compare taux de réussite et temps de résolution sur un même échantillon ; ne basculez la production qu'une fois les chiffres validés, puis surveillez 24 heures.
Quel plan CaptchaAI choisir en quittant AZCaptcha ?
CaptchaAI facture par thread simultané, pas par résolution : chaque plan inclut des résolutions illimitées par thread. Commencez par BASIC ($15/mois, 5 threads), puis montez vers STANDARD ($30/mois, 15 threads) ou ADVANCE ($90/mois, 50 threads) selon votre concurrence. Facturation en dollars US.
CaptchaAI résout-il les mêmes CAPTCHA qu'AZCaptcha ?
Oui pour l'essentiel : reCAPTCHA v2 et v3, Cloudflare Turnstile et Challenge, GeeTest v3, les CAPTCHA image/OCR et en grille. hCaptcha et FunCaptcha (Arkose Labs) ne sont pas pris en charge, et GeeTest v4 est annoncé « à venir ». Vérifiez vos types avant de basculer.
Et ensuite ?
Vous avez tout pour basculer : créez votre clé API CaptchaAI et migrez en quelques minutes.
Guides associés :
- la correspondance des endpoints
- le test en parallèle pendant une migration
- pourquoi les équipes changent de fournisseur