O saldo da API zera de madrugada, a taxa de erro do reCAPTCHA dispara depois de um deploy e ninguém percebe até o primeiro ticket de suporte. É esse o problema que a observabilidade resolve: em vez de descobrir a falha pela reclamação do cliente, você descobre pelo alerta — minutos antes. Este guia mostra quais métricas do pipeline de CAPTCHA da CaptchaAI vale a pena rastrear no Datadog, como enviá-las via DogStatsD em Python e Node.js, como montar o painel e quais alertas configurar primeiro.
Métricas essenciais para monitorar o pipeline CaptchaAI
Sete métricas cobrem praticamente todo incidente relevante: volume, sucesso, erro, latência, fila, saldo e saúde dos workers. Comece por elas antes de instrumentar qualquer coisa mais específica.
| Métrica | Tipo | Por que é importante |
|---|---|---|
captcha.solve.count |
Contador | Total de tarefas enviadas — sua linha de base de volume |
captcha.solve.success |
Contador | Soluções bem-sucedidas — numerador da taxa de sucesso |
captcha.solve.error |
Contador | Falhas por tipo de erro — onde cavar primeiro num incidente |
captcha.solve.latency |
Histograma | Tempo entre envio e solução — base dos alertas de p95/p99 |
captcha.queue.depth |
Medidor | Tarefas pendentes na fila — sinal antecipado de gargalo |
captcha.balance |
Medidor | Saldo restante na conta CaptchaAI |
captcha.worker.active |
Medidor | Processos worker ativos no host |
Enviando métricas do CaptchaAI ao Datadog em Python (DogStatsD)
O caminho mais direto é um decorator que envolve a função de resolução e publica contador de envio, contador de sucesso/erro e histograma de latência a cada chamada, sem espalhar código de métrica pelo pipeline inteiro.
import os
import time
import functools
import requests
from datadog import initialize, statsd
# Initialize Datadog
initialize(
statsd_host=os.environ.get("DD_AGENT_HOST", "localhost"),
statsd_port=int(os.environ.get("DD_DOGSTATSD_PORT", "8125"))
)
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
session = requests.Session()
def track_captcha_metrics(captcha_type="recaptcha_v2"):
"""Decorator to track solve metrics."""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
tags = [f"captcha_type:{captcha_type}"]
statsd.increment("captcha.solve.count", tags=tags)
start = time.time()
try:
result = func(*args, **kwargs)
elapsed = time.time() - start
if "solution" in result:
statsd.increment("captcha.solve.success", tags=tags)
statsd.histogram("captcha.solve.latency", elapsed, tags=tags)
else:
error = result.get("error", "unknown")
statsd.increment(
"captcha.solve.error",
tags=tags + [f"error:{error}"]
)
return result
except Exception as e:
statsd.increment(
"captcha.solve.error",
tags=tags + [f"error:{type(e).__name__}"]
)
raise
return wrapper
return decorator
@track_captcha_metrics(captcha_type="recaptcha_v2")
def solve_recaptcha(sitekey, pageurl):
resp = session.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"]
for _ in range(60):
time.sleep(5)
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:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
def report_balance():
"""Send balance as a gauge metric."""
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"])
statsd.gauge("captcha.balance", balance)
return balance
return None
def report_queue_depth(depth):
"""Report current queue depth."""
statsd.gauge("captcha.queue.depth", depth)
def report_worker_count(active, total):
"""Report worker health."""
statsd.gauge("captcha.worker.active", active)
statsd.gauge("captcha.worker.total", total)
Repare que track_captcha_metrics é um decorator reaproveitável: qualquer função de resolução — reCAPTCHA, Turnstile, GeeTest v3 — ganha as mesmas três métricas só por receber a anotação, com captcha_type na tag para segmentar depois no Datadog.
Enviando métricas do CaptchaAI ao Datadog em Node.js
Em Node.js, a lib hot-shots cobre o mesmo papel do DogStatsD Python, com globalTags fixando o ambiente (env:production, env:staging) em toda métrica emitida pelo processo.
const { StatsD } = require("hot-shots");
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
const dogstatsd = new StatsD({
host: process.env.DD_AGENT_HOST || "localhost",
port: parseInt(process.env.DD_DOGSTATSD_PORT || "8125", 10),
prefix: "captcha.",
globalTags: [`env:${process.env.NODE_ENV || "development"}`],
});
async function solveCaptchaWithMetrics(sitekey, pageurl, captchaType = "recaptcha_v2") {
const tags = [`captcha_type:${captchaType}`];
dogstatsd.increment("solve.count", 1, tags);
const startTime = Date.now();
try {
const result = await solveCaptcha(sitekey, pageurl);
const elapsed = (Date.now() - startTime) / 1000;
if (result.solution) {
dogstatsd.increment("solve.success", 1, tags);
dogstatsd.histogram("solve.latency", elapsed, tags);
} else {
dogstatsd.increment("solve.error", 1, [...tags, `error:${result.error}`]);
}
return result;
} catch (err) {
dogstatsd.increment("solve.error", 1, [...tags, `error:${err.message}`]);
throw err;
}
}
async function solveCaptcha(sitekey, pageurl) {
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) {
return { error: submitResp.data.request };
}
const captchaId = submitResp.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
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) return { solution: pollResp.data.request };
if (pollResp.data.request !== "CAPCHA_NOT_READY") {
return { error: pollResp.data.request };
}
}
return { error: "TIMEOUT" };
}
async function reportBalance() {
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);
dogstatsd.gauge("balance", balance);
return balance;
}
} catch (err) {
console.error("Balance check failed:", err.message);
}
return null;
}
// Report balance every minute
setInterval(reportBalance, 60000);
module.exports = { solveCaptchaWithMetrics, reportBalance };
Se os workers rodam numa região próxima do Brasil (por exemplo, sa-east-1 na AWS, São Paulo), lembre-se de que o RTT até o endpoint da CaptchaAI se soma ao tempo total de resolução — vale medir a latência de rede isolada antes de calibrar o limite de alerta de p95 abaixo, para não confundir latência de rede com lentidão do solver.
Painel do Datadog para o pipeline CaptchaAI
Este JSON já vem pronto com quatro widgets — taxa de sucesso vs. erro, percentis de latência, saldo atual e profundidade da fila. Importe direto no Datadog para ter o painel de pé em minutos, sem montar cada gráfico manualmente.
{
"title": "CaptchaAI Pipeline",
"widgets": [
{
"definition": {
"type": "timeseries",
"title": "Solve Rate (Success vs Error)",
"requests": [
{"q": "sum:captcha.solve.success{*}.as_count()"},
{"q": "sum:captcha.solve.error{*}.as_count()"}
]
}
},
{
"definition": {
"type": "timeseries",
"title": "Solve Latency (p50, p95, p99)",
"requests": [
{"q": "avg:captcha.solve.latency{*}"},
{"q": "percentile:captcha.solve.latency{*},0.95"},
{"q": "percentile:captcha.solve.latency{*},0.99"}
]
}
},
{
"definition": {
"type": "query_value",
"title": "API Balance",
"requests": [{"q": "avg:captcha.balance{*}"}]
}
},
{
"definition": {
"type": "timeseries",
"title": "Queue Depth",
"requests": [{"q": "avg:captcha.queue.depth{*}"}]
}
}
]
}
Ao criar tags customizadas em cima destas métricas, evite incluir dados pessoais do usuário final (e-mail, CPF, IP completo) nos valores das tags — mantém o diagnóstico útil e a coleta alinhada à LGPD sem perder granularidade.
Alertas do Datadog para saldo, erro e fila da CaptchaAI
Seis alertas cobrem os cenários que realmente derrubam um pipeline em produção: saldo zerando, taxa de erro subindo, latência disparando, fila entupindo e worker morto.
| Alerta | Condição | Gravidade |
|---|---|---|
| Saldo baixo | captcha.balance < 10 |
Aviso |
| Saldo crítico | captcha.balance < 2 |
Crítico |
| Alta taxa de erro | Taxa de erro > 10% em 5 minutos | Aviso |
| Pico de latência | Latência p95 > 120 s em 10 minutos | Aviso |
| Fila entupindo | Profundidade da fila > 100, crescendo por 5 min | Aviso |
| Worker inativo | captcha.worker.active == 0 |
Crítico |
# Datadog monitor definition (API create)
- type: metric alert
name: "CaptchaAI Low Balance"
query: "avg(last_5m):avg:captcha.balance{*} < 10"
message: "CaptchaAI balance is low: {{value}}. Top up to avoid solve failures."
tags:
- team:scraping
- service:captcha
Comece pelos dois alertas de saldo — são os mais baratos de configurar e os que mais evitam interrupção total do pipeline por falta de crédito.
Problemas comuns no monitoramento CaptchaAI + Datadog
| Problema | Causa | Correção |
|---|---|---|
| Métricas não aparecem | Agente DogStatsD não está em execução | Verifique DD_AGENT_HOST; confira docker ps para o contêiner do agente |
| Histograma de latência vazio | Nenhuma solução bem-sucedida foi rastreada | Confirme que statsd.histogram() é chamado no caminho de sucesso |
| Tags faltando | Formato de tag incorreto | Use o formato key:value, sem espaços dentro da tag |
| Métricas duplicadas | Vários repórteres em execução simultânea | Garanta apenas um relator de saldo por implantação |
Perguntas frequentes
Preciso de um agente do Datadog em cada worker do pipeline?
Não. Rode um agente DogStatsD por host. Todos os workers desse host enviam as métricas para o agente local, que as encaminha para o intake do Datadog — não é preciso um agente por processo.
Como evito estourar o limite de séries temporais personalizadas no Datadog?
A cardinalidade explode quando você inclui valores de alta variação nas tags — como captcha_id ou IP do usuário. Use apenas tags de baixa cardinalidade (captcha_type, env, region) e deixe identificadores únicos nos logs, não nas tags de métrica.
Esses alertas servem também para Cloudflare Turnstile e GeeTest v3, ou só para reCAPTCHA?
Servem para qualquer tipo suportado pela CaptchaAI. Basta variar a tag captcha_type (turnstile, geetest_v3, recaptcha_v2 etc.) — as métricas captcha.solve.* e os alertas de saldo e fila são agnósticos ao tipo de desafio.
Consigo montar esse painel usando só a API HTTP do Datadog, sem instalar o agente DogStatsD?
Sim, é possível enviar métricas via API HTTP do Datadog, mas o DogStatsD (UDP local) tem menor overhead por chamada e é o caminho recomendado para pipelines de alto volume — a API HTTP costuma valer mais para reportar métricas agregadas em batch, não por solve individual.
Vale a pena combinar isso com o Datadog APM, ou as métricas customizadas já bastam?
As métricas customizadas cobrem a maior parte dos alertas operacionais. O Datadog APM (via ddtrace) soma valor quando você precisa investigar uma chamada lenta específica dentro de uma transação maior — os dois se complementam, não competem.
Artigos relacionados
- Como construir um sistema de monitoramento de avaliações com a CaptchaAI
- Como construir um bot de monitoramento de mudanças de conteúdo com a CaptchaAI
- Painel de uso da CaptchaAI: como montar
Próximos passos
Leve observabilidade real ao seu pipeline de CAPTCHA — comece com uma chave de API da CaptchaAI e conecte-a ao Datadog ainda hoje.
Guias relacionados: