Un pipeline de résolution de CAPTCHA tombe en panne sans prévenir : le taux de réussite s'effrite, la latence grimpe pendant un pic de trafic, et vous ne le découvrez qu'au moment où vos scripts se figent. New Relic APM supprime cet angle mort en reliant chaque résolution — de l'envoi de la tâche à la livraison du token — à une transaction traçable et à des événements que vous interrogez en temps réel.
Ce guide montre comment instrumenter votre pipeline CaptchaAI de bout en bout : envoyer des événements personnalisés depuis Python et Node.js, construire un tableau de bord NRQL, puis déclencher des alertes sur le taux de réussite, la latence et le solde. Vous gardez la même API CaptchaAI ; vous y ajoutez la couche d'observabilité qui manquait.
Ce qu'il faut surveiller dans un pipeline de résolution
Trois phases méritent une mesure distincte : l'envoi de la tâche, l'attente de la solution (le polling) et l'application du token. Chacune a sa propre latence et son propre mode d'échec, et c'est en les séparant que vous saurez où corriger quand un incident survient.
- Envoi de la tâche : latence de l'appel
in.phpet taux d'erreurs de soumission (clé invalide, sitekey manquant). - Attente de la solution : durée du polling, nombre d'interrogations et taux de timeout.
- Application du token : taux de réussite final, mesuré une fois le token injecté dans la page cible.
[Submit Task] → [Wait for Solution] → [Apply Token]
↓ ↓ ↓
Submit latency Poll duration Token usage
API errors Timeout rate Success rate
Prérequis
Avant d'instrumenter votre pipeline, réunissez les éléments suivants :
- Un compte New Relic et sa clé de licence (« license key »).
- L'agent
newrelicinstallé côté serveur (pip install newrelicounpm install newrelic). - Votre clé API CaptchaAI exposée dans une variable d'environnement (
CAPTCHAAI_API_KEY). - Un pipeline de résolution déjà fonctionnel : l'instrumentation observe le flux existant, elle ne le remplace pas.
Python : instrumenter CaptchaAI avec New Relic
Le décorateur background_task transforme chaque résolution en transaction New Relic, tandis que record_custom_event publie les métriques métier — type de CAPTCHA, temps de résolution, code d'erreur. Le module ci-dessous couvre les trois phases et remonte aussi le solde du compte.
import os
import time
import requests
import newrelic.agent
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
session = requests.Session()
@newrelic.agent.background_task(name="captcha_solve", group="CaptchaAI")
def solve_captcha(sitekey, pageurl, captcha_type="recaptcha_v2"):
"""Solve a CAPTCHA with full New Relic instrumentation."""
# Add custom attributes for filtering
newrelic.agent.add_custom_attributes([
("captcha_type", captcha_type),
("target_url", pageurl),
])
# Submit phase
submit_result = _submit_task(sitekey, pageurl, captcha_type)
if "error" in submit_result:
newrelic.agent.record_custom_event("CaptchaSolveError", {
"error": submit_result["error"],
"phase": "submit",
"captcha_type": captcha_type,
})
return submit_result
# Poll phase
captcha_id = submit_result["captcha_id"]
poll_result = _poll_result(captcha_id, captcha_type)
# Record solve event
event_data = {
"captcha_type": captcha_type,
"captcha_id": captcha_id,
"success": "solution" in poll_result,
}
if "solution" in poll_result:
event_data["solve_time"] = poll_result.get("elapsed", 0)
newrelic.agent.record_custom_event("CaptchaSolveSuccess", event_data)
else:
event_data["error"] = poll_result.get("error", "unknown")
newrelic.agent.record_custom_event("CaptchaSolveError", event_data)
return poll_result
@newrelic.agent.function_trace(name="captcha_submit")
def _submit_task(sitekey, pageurl, captcha_type):
payload = {
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
}
resp = session.post("https://ocr.captchaai.com/in.php", data=payload)
data = resp.json()
newrelic.agent.add_custom_attributes([
("submit_status", data.get("status")),
])
if data.get("status") != 1:
return {"error": data.get("request")}
return {"captcha_id": data["request"]}
@newrelic.agent.function_trace(name="captcha_poll")
def _poll_result(captcha_id, captcha_type):
start = time.time()
poll_count = 0
for _ in range(60):
time.sleep(5)
poll_count += 1
result = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
elapsed = time.time() - start
newrelic.agent.add_custom_attributes([
("poll_count", poll_count),
("solve_time_seconds", round(elapsed, 2)),
])
return {"solution": result["request"], "elapsed": elapsed}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
def report_balance():
"""Record balance as a custom event."""
resp = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "getbalance", "json": 1
})
data = resp.json()
if data.get("status") == 1:
balance = float(data["request"])
newrelic.agent.record_custom_event("CaptchaBalance", {
"balance": balance,
"low": balance < 10,
})
return balance
return None
Configuration de l'agent New Relic
Activez les événements personnalisés et abaissez le seuil du traceur de transactions pour capturer les résolutions lentes. Sans custom_insights_events.enabled, vos événements CaptchaSolveSuccess n'atteignent jamais New Relic.
# newrelic.ini
[newrelic]
app_name = CaptchaAI Pipeline
license_key = YOUR_NEW_RELIC_LICENSE_KEY
monitor_mode = true
log_level = info
transaction_tracer.enabled = true
transaction_tracer.transaction_threshold = 5.0
custom_insights_events.enabled = true
custom_insights_events.max_samples_stored = 5000
JavaScript : intégrer l'agent New Relic
Côté Node.js, startBackgroundTransaction encadre la résolution et recordCustomEvent publie exactement les mêmes événements que la version Python. Vous partagez ainsi un tableau de bord unique entre vos services, quel que soit leur langage.
const newrelic = require("newrelic");
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
async function solveCaptchaWithNewRelic(sitekey, pageurl, captchaType = "recaptcha_v2") {
return newrelic.startBackgroundTransaction(
"CaptchaSolve",
"CaptchaAI",
async () => {
const transaction = newrelic.getTransaction();
newrelic.addCustomAttributes({
captchaType,
targetUrl: pageurl,
});
const startTime = Date.now();
try {
// Submit
const submitResp = await axios.post(
"https://ocr.captchaai.com/in.php",
null,
{
params: {
key: API_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageurl,
json: 1,
},
}
);
if (submitResp.data.status !== 1) {
newrelic.recordCustomEvent("CaptchaSolveError", {
error: submitResp.data.request,
phase: "submit",
captchaType,
});
transaction.end();
return { error: submitResp.data.request };
}
const captchaId = submitResp.data.request;
newrelic.addCustomAttributes({ captchaId });
// Poll
let pollCount = 0;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
pollCount++;
const pollResp = await axios.get(
"https://ocr.captchaai.com/res.php",
{
params: {
key: API_KEY, action: "get", id: captchaId, json: 1,
},
}
);
if (pollResp.data.status === 1) {
const elapsed = (Date.now() - startTime) / 1000;
newrelic.recordCustomEvent("CaptchaSolveSuccess", {
captchaType,
solveTime: elapsed,
pollCount,
});
newrelic.addCustomAttributes({
solveTime: elapsed,
pollCount,
});
transaction.end();
return { solution: pollResp.data.request, elapsed };
}
if (pollResp.data.request !== "CAPCHA_NOT_READY") {
newrelic.recordCustomEvent("CaptchaSolveError", {
error: pollResp.data.request,
phase: "poll",
captchaType,
});
transaction.end();
return { error: pollResp.data.request };
}
}
newrelic.recordCustomEvent("CaptchaSolveError", {
error: "TIMEOUT",
phase: "poll",
captchaType,
pollCount,
});
transaction.end();
return { error: "TIMEOUT" };
} catch (err) {
newrelic.noticeError(err);
transaction.end();
throw err;
}
}
);
}
// Balance monitoring
async function monitorBalance() {
try {
const resp = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "getbalance", json: 1 },
});
if (resp.data.status === 1) {
const balance = parseFloat(resp.data.request);
newrelic.recordCustomEvent("CaptchaBalance", { balance });
}
} catch (err) {
newrelic.noticeError(err);
}
}
setInterval(monitorBalance, 60000);
module.exports = { solveCaptchaWithNewRelic };
Requêtes NRQL pour votre tableau de bord
Assemblez un tableau de bord New Relic à partir de ces requêtes NRQL. Elles couvrent quatre angles complémentaires :
- le taux de réussite global et le débit de tâches par minute ;
- le temps de résolution moyen et la latence P95, ventilés par type de CAPTCHA ;
- la répartition des erreurs, pour isoler le code fautif ;
- l'évolution du solde, échantillonnée toutes les 5 minutes.
-- Solve success rate (last hour)
SELECT percentage(count(*), WHERE success = true)
FROM CaptchaSolveSuccess, CaptchaSolveError
SINCE 1 hour ago
-- Average solve time by CAPTCHA type
SELECT average(solveTime)
FROM CaptchaSolveSuccess
FACET captchaType
SINCE 1 hour ago TIMESERIES
-- Error breakdown
SELECT count(*)
FROM CaptchaSolveError
FACET error
SINCE 1 hour ago
-- P95 solve latency
SELECT percentile(solveTime, 95)
FROM CaptchaSolveSuccess
SINCE 1 hour ago TIMESERIES
-- Balance over time
SELECT latest(balance)
FROM CaptchaBalance
SINCE 24 hours ago TIMESERIES 5 minutes
-- Tasks per minute
SELECT rate(count(*), 1 minute)
FROM CaptchaSolveSuccess, CaptchaSolveError
SINCE 1 hour ago TIMESERIES
Les alertes à configurer
Un tableau de bord se regarde ; une alerte vous réveille. Configurez au minimum ces quatre conditions pour être prévenu avant vos utilisateurs.
| Alerte | Condition NRQL | Seuil |
|---|---|---|
| Taux de réussite faible | SELECT percentage(count(*), WHERE success = true) |
< 85 % pendant 5 min |
| Latence élevée | SELECT percentile(solveTime, 95) FROM CaptchaSolveSuccess |
> 120 s pendant 10 min |
| Solde faible | SELECT latest(balance) FROM CaptchaBalance |
< 10 $ |
| Pic d'erreurs | SELECT count(*) FROM CaptchaSolveError |
> 50 en 5 min |
Corréler la latence par région et rester conforme au RGPD
Si vos workers tournent sur plusieurs régions — par exemple eu-west-3 (Paris) chez AWS, ou une instance OVHcloud à Gravelines — ajoutez un attribut region à chaque transaction. Une requête FACET region révèle alors si la latence de résolution dépend de l'emplacement de vos workers plutôt que de l'API CaptchaAI elle-même.
Quelques attributs utiles à ajouter, sans jamais y glisser de données personnelles :
region: la région d'exécution du worker (eu-west-3,grachez OVHcloud).worker_host: l'identifiant machine, pour repérer un nœud défaillant.plan_tier: le palier CaptchaAI utilisé, afin de corréler saturation et concurrence.
Côté conformité, gardez vos attributs personnalisés propres : n'y placez jamais d'adresse e-mail, d'identifiant utilisateur ni d'URL contenant des données personnelles. Le principe de minimisation du RGPD s'applique aussi à votre télémétrie — un target_url générique suffit, une URL avec un e-mail en paramètre est à proscrire.
Dépannage
| Problème | Cause | Correctif |
|---|---|---|
| Les événements personnalisés n'apparaissent pas | custom_insights_events.enabled est à false |
Activez-le dans newrelic.ini |
| Traces de transaction absentes | Seuil trop élevé | Abaissez transaction_threshold à 1,0 s |
| Attributs tronqués | Valeur trop longue | Gardez les valeurs d'attribut sous 255 caractères |
| Aucune donnée après le déploiement | Clé de licence erronée ou agent non démarré | Vérifiez avec newrelic-admin validate-config newrelic.ini |
FAQ
Comment mesurer le taux de réussite par type de CAPTCHA dans New Relic ?
Facettez l'événement CaptchaSolveSuccess par captchaType. Une requête NRQL avec FACET captchaType sépare reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile et GeeTest v3, ce qui vous permet de repérer le type qui tire votre taux de réussite global vers le bas.
Comment relier une alerte de solde faible à la capacité de mon plan CaptchaAI ?
L'événement CaptchaBalance suit votre solde ; l'alerte vous prévient avant qu'il ne s'épuise. La concurrence, elle, dépend de votre plan : de BASIC ($15/mois, 5 threads) à ADVANCE ($90/mois, 50 threads), chaque palier fixe le nombre de résolutions simultanées. Surveillez poll_count et le débit par minute pour savoir si vous saturez vos threads et s'il est temps de monter d'un cran.
Pourquoi mes événements personnalisés n'apparaissent-ils pas dans New Relic ?
Vérifiez d'abord que custom_insights_events.enabled = true dans newrelic.ini, puis que la clé de licence est correcte et que l'agent démarre bien. Les événements peuvent aussi mettre une à deux minutes à remonter ; laissez tourner un cycle complet avant de conclure à un problème.
L'agent New Relic ralentit-il la résolution des CAPTCHA ?
Non, de façon négligeable. L'agent ajoute quelques microsecondes par appel instrumenté. Face à des temps de résolution de 5 à 120 secondes, ce surcoût reste invisible dans vos mesures.
Articles connexes
- l'intégration CaptchaAI avec Google Cloud Functions
- le scraping moderne avec Crawlee et CaptchaAI
- construire un système de surveillance des avis
Prochaines étapes
Donnez à votre pipeline CAPTCHA une visibilité complète : démarrez avec une clé API CaptchaAI, branchez l'agent New Relic et vos premiers événements remontent en quelques minutes.
Guides associés :
- la supervision avec Datadog
- Prometheus et Grafana
- le tableau de bord d'utilisation