Developer guideReports and data

Reports and data

What a record holds and never holds, how long it is kept, the challenge funnel, attack timelines and the metrics a self-hosted service exposes.

What a record holds

Every verification, every server check and every funnel beacon is recorded as one line. Records exist so that a question about your traffic can be answered from data rather than memory: which check ran, why, with which version of the rules, and what came of it.

JSON
// One verification record, abridged. One JSON object per line.
{
  "time": "2026-11-04T09:12:41Z",
  "type": "verify",
  "captcha_id": "[SITE KEY]",
  "lot_number": "3f9c2b6e4d1a4f0b9c8e7d6a5b4c3d2e",
  "site": "https://www.example.com",
  "tier": "normal",
  "outcome": "hold",
  "score": 60, "would_score": 75,
  "checks": ["ip_rate"], "measured": ["no_sec_fetch"],
  "net_score": 60, "browser_score": 0,
  "solve_ms": 412, "engine": "wasm",
  "loader_version": "1.2.1",
  "attack_level": 0,
  "browser": "Chrome", "browser_major": 142, "device_class": "desktop", "language": "en",
  "country": "DE", "asn": 3320,
  "ip_hash": "…", "device_hash": "…",
  "rules_version": 3
}
GroupFields
The attemptTime, record type (verify, validate or funnel), site key, lot number, the page origin the check ran on, the tier, the outcome and, for a server check, the code.
The decisionThe score and the "would" score with the measured checks counted; the checks that fired and the ones that were only measured; the same split into network and browser scores; for a slide, the shape of the drag and whether the trace check would have refused it; the attack level at the time; whether measured checks were enforced for the site.
The deviceBrowser family and major version, device class, screen class, page language, how long the solve took and in which engine, and the loader version.
The networkCountry and autonomous system number, as seen at our edge.
IdentifiersThe address and the device fingerprint only as keyed hashes under a salt that changes every day, so the same visitor can be counted within a day and not linked across days. Repeat counts within the day for the address, the device and a near-empty browser profile.
ProvenanceThe version of the scoring rules that produced the record.

What a record never holds

Form contents, passwords, e-mail addresses, cookies, the page's HTML, or anything typed on your page. The loader does not have access to your form and sends none of it. Addresses are never written to a record in clear; the only place an address exists in clear is the rate counter in the store, which expires within a minute.

How long

Detailed records are kept for 90 days, then deleted. Daily totals without identifiers are kept beyond that, so long-term trends survive the deletion. The final periods will be confirmed in our privacy notice. A self-hosted service sets its own retention; see Self-hosting.

The challenge funnel

A visitor who gives up on a hold or a puzzle never reaches your server, so the records above cannot show them. The loader therefore sends one beacon when a box ends, with four counts and how it ended. It is measure only: nothing reads it for a verdict, the loader never waits for it, and it has its own rate counter so that it cannot raise anyone's score.

JSON
{ "type": "funnel", "tier": "puzzle", "outcome": "alt", "funnel": { "started": 2, "early": 0, "done": 2, "missed": 2 }, … }
EndMeaning
passThe visitor finished the check.
closedThey closed the box.
leftThey left the page with the box open.
altThey switched from the puzzle to the hold.
offlineThe service could not be reached and an offline pass was made.

The counts are started (holds or drags begun), early (released too soon), done (holds completed or drags submitted) and missed (attempts the service refused). Each box counts once, only a box's own signed challenge is accepted, and a beacon can be lost when a browser extension blocks it or the browser is killed, so treat the funnel as a floor. Loaders before 1.2.0 send nothing, so compare funnels only within a loader version.

Reports

ReportWhat it answers
Weekly reportTraffic for the week, outcomes by tier, attack episodes, new top networks, solve time by device class, and what the measured checks would have done had they counted.
Attack timelinesEvery automatic level change is kept as one episode: when it started, which trigger raised it, which networks and countries took part, and when it ended.
Sites that never verifyA site key that shows the check in browsers but whose server never confirms a pass is unprotected. The records make it visible, so an integration gap is found before an attacker finds it.
Loader versions and the funnelBoth are in the records: every attempt and every beacon names the loader version that sent it, so a self-hosted copy that has fallen behind is visible, and the funnel can be read per version.

Today the reports are prepared on our side and sent to you. A self-service view is planned.

Metrics on a self-hosted service

The metrics listener serves Prometheus text. The counters most worth graphing and alerting on:

MetricLabelsMeaning
otcaptcha_load_totalresult, originChallenges issued, or refused for an unknown key.
otcaptcha_verify_totalresult, originVerifications by outcome; a refusal carries its reason as the result.
otcaptcha_validate_totalresult, codeServer checks decided, success or fail by code.
otcaptcha_validate_5xx_totalreasonServer checks that could not be decided: store, overload or slow body. Alert on any rise.
otcaptcha_validate_refused_totalServer checks from an address outside the allow-list.
otcaptcha_offline_token_totalOffline passes refused: browsers that could not reach the public listener while your server could.
otcaptcha_solve_msHistogram of solve times reported by browsers.
otcaptcha_solve_engine_totalengineSolves in WebAssembly, JavaScript workers or on the main thread.
otcaptcha_risk_signal_total, otcaptcha_risk_measured_totalsignalChecks that fired and counted, and checks that fired and were only measured.
otcaptcha_attack_level_changes_totalAutomatic level changes. Each one is also logged.
otcaptcha_funnel_total, otcaptcha_funnel_refused_totaltier, end / reasonBox ends by tier and outcome; beacons refused as malformed or rate-limited.
otcaptcha_puzzle_total, otcaptcha_puzzle_trace_totalresult / shapePuzzles solved or missed; drag trace shapes.
otcaptcha_store_errors_totalopStore failures by operation. Alert on any rise.