Steigen die Antwortzeiten Ihrer Automatisierung, ist die entscheidende Frage: liegt es an Ihrem Code oder an der CAPTCHA-Lösung? Ohne eigene Instrumentierung bleibt dieser Schritt in New Relic eine Blackbox. Mit wenigen Custom Events machen Sie jede Übermittlung an CaptchaAI, jede Poll-Dauer und jede Fehlerquote sichtbar – von der Aufgabe bis zum fertigen Token. Dieser Leitfaden zeigt die Instrumentierung in Python und Node.js sowie die passenden NRQL-Abfragen und Alerts.
Standard-APM zeigt Ihnen HTTP-Aufrufe und Datenbankabfragen, behandelt die externe CAPTCHA-Lösung aber als einen einzigen ausgehenden Request. Ob dieser Request 8 oder 90 Sekunden dauert, ob er an der Übermittlung oder am Polling hängt und wie hoch die Erfolgsquote je CAPTCHA-Typ ist, sehen Sie erst mit eigenen Custom Events. Genau diese Lücke schließen die folgenden Beispiele – ohne dass Sie Ihre bestehende Solver-Logik umbauen müssen.
Was Sie in der CAPTCHA-Pipeline überwachen sollten
Eine CAPTCHA-Lösung durchläuft drei Phasen mit eigenen Latenz- und Fehlerquellen: Übermitteln der Aufgabe, Abfragen des Ergebnisses (Polling) und Einsetzen des Tokens.
[Submit Task] → [Wait for Solution] → [Apply Token]
↓ ↓ ↓
Submit latency Poll duration Token usage
API errors Timeout rate Success rate
Die Übermittlungslatenz spiegelt die Erreichbarkeit der API wider, die Poll-Dauer entspricht der eigentlichen Lösungszeit und hängt vom CAPTCHA-Typ ab, und die Token-Nutzung zeigt, ob Ihre Automatisierung das Ergebnis rechtzeitig einsetzt – Tokens laufen nach rund 120 Sekunden ab. Messen Sie alle drei Phasen getrennt, sonst verschwimmt ein API-Ausfall mit einem langsamen Solver zu einer einzigen unklaren Kennzahl.
Python: CaptchaAI mit New Relic instrumentieren
Die folgende Instrumentierung kapselt eine reCAPTCHA-v2-Lösung als New-Relic-Background-Task. add_custom_attributes hängt captcha_type und target_url an die Transaktion, sodass Sie das Dashboard später nach Typ oder Zielseite filtern können. record_custom_event schreibt bei Erfolg ein CaptchaSolveSuccess- und bei Fehlern ein CaptchaSolveError-Event – jeweils mit Phase und Fehlercode, damit Sie Submit- von Poll-Fehlern unterscheiden. Die eigentliche Solver-Logik bleibt unverändert.
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
New Relic-Agent konfigurieren (newrelic.ini)
custom_insights_events.enabled = true ist Pflicht – sonst verwirft der Agent Ihre Events stillschweigend:
# 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
Hinweis für DACH-Teams: Das Attribut target_url kann personenbezogene Daten enthalten. Prüfen Sie unter DSGVO, welche URLs Sie an New Relic senden, und maskieren Sie sensible Werte vorab. In GitLab-CI-Pipelines, die in vielen deutschen Teams Standard sind, hinterlegen Sie den license_key als maskierte CI-Variable statt fest in der newrelic.ini.
Node.js: dieselbe Instrumentierung in JavaScript
Für JavaScript-Worker – etwa unter Node.js auf einem Hetzner-VPS oder in AWS Lambda – gilt dasselbe Muster:
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 };
NRQL-Abfragen für Ihr Dashboard
Diese Abfragen bilden ein Dashboard mit Erfolgsquote, Lösungszeit nach Typ, Fehleraufschlüsselung und Guthabenverlauf – ein Widget pro Abfrage:
-- 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
Erfolgsquote und P95-Latenz gehören auf die oberste Dashboard-Zeile. Die Fehleraufschlüsselung per FACET error zeigt sofort, ob ein einzelner Fehlercode dominiert – etwa wiederholte Timeouts oder ein ungültiger Sitekey –, und der Guthabenverlauf verhindert, dass eine Pipeline unbemerkt wegen leeren Guthabens stoppt.
Alert-Policies für Lösungsrate und Guthaben
Übersetzen Sie die wichtigsten Abfragen in Alert-Policies. Besonders wertvoll ist der Guthaben-Alert: Fällt das CaptchaBalance-Event unter die Schwelle, warnt New Relic, bevor Aufgaben scheitern.
| Alarm | NRQL-Bedingung | Schwelle |
|---|---|---|
| Niedrige Lösungsrate | SELECT percentage(count(*), WHERE success = true) |
< 85 % für 5 Min |
| Hohe Latenz | SELECT percentile(solveTime, 95) FROM CaptchaSolveSuccess |
> 120 s für 10 Min |
| Niedriges Guthaben | SELECT latest(balance) FROM CaptchaBalance |
< 10 $ |
| Fehlerspitze | SELECT count(*) FROM CaptchaSolveError |
> 50 in 5 Min |
Setzen Sie die Schwellen an Ihrem realen Traffic aus. Eine Lösungsrate unter 85 % über fünf Minuten deutet meist auf einen falschen Sitekey, eine geänderte Zielseite oder ein Upstream-Problem hin – selten auf CaptchaAI selbst. Ein zu enges Fenster erzeugt Alarm-Rauschen, ein zu weites verschleppt echte Ausfälle.
Häufige Fehler und Lösungen
Fehlen Metriken oder Traces, liegt es fast immer an der Agent-Konfiguration:
| Problem | Ursache | Lösung |
|---|---|---|
| Custom Metrics erscheinen nicht in New Relic | License Key fehlt oder New Relic Agent nicht initialisiert | newrelic.agent.initialize() prüfen, License Key in Umgebungsvariable setzen |
| APM-Trace zeigt keine CAPTCHA-Spans | newrelic.agent.record_custom_event nicht aufgerufen |
Instrumentierung im Solver-Code validieren |
| Alerts feuern nicht | NRQL-Bedingung oder Schwellenwert falsch konfiguriert | Alert-Policy und Bedingung in New Relic One überprüfen |
| Metriken fehlen nach Neustart | New Relic Agent nicht in requirements.txt |
newrelic-Paket installieren und Agent beim Start laden |
Validieren Sie die Konfiguration nach jedem Deploy mit newrelic-admin validate-config newrelic.ini, bevor Sie in New Relic nach dem fehlenden Signal suchen – die häufigste Ursache ist ein falsch gesetzter oder fehlender License Key.
FAQ
Welche NRQL-Abfragen sollte ein CAPTCHA-Dashboard mindestens enthalten?
Erfolgsquote, Lösungszeit im P95 nach CAPTCHA-Typ und eine Fehleraufschlüsselung. Damit erkennen Sie einen Einbruch pro Typ, bevor er den gesamten Workflow bremst.
Wie richte ich eine Warnung für niedriges Guthaben ein?
Über das CaptchaBalance-Event und die Bedingung SELECT latest(balance) FROM CaptchaBalance mit einer Schwelle unter 10 $. So laden Sie Guthaben nach, bevor Aufgaben scheitern.
Beeinflusst der gewählte CaptchaAI-Tarif das Monitoring?
Nein. CaptchaAI rechnet pro Thread ab – von BASIC (15 $/Monat, 5 Threads) bis VIP-3 (7.500 $/Monat, 5.000 Threads). Mehr Threads liefern dichtere Messdaten, erfordern aber dieselbe Instrumentierung.
Lassen sich Python- und Node.js-Worker gemeinsam auswerten?
Ja. Beide senden dieselben Event-Namen; eine NRQL-Abfrage ohne Sprachfilter aggregiert alle Worker über die gesamte Pipeline.
Wie viele Poll-Anfragen sind pro Lösung normal?
Im Beispiel fragt der Code alle fünf Sekunden ab, bis zu 60-mal. Die meisten reCAPTCHA-v2- und Turnstile-Lösungen sind nach wenigen Durchläufen fertig; ein durchgehend hoher poll_count ist ein Frühwarnsignal für Auslastung oder Timeouts und gehört als eigenes Widget ins Dashboard.