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.
// 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
}| Group | Fields |
|---|---|
| The attempt | Time, 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 decision | The 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 device | Browser family and major version, device class, screen class, page language, how long the solve took and in which engine, and the loader version. |
| The network | Country and autonomous system number, as seen at our edge. |
| Identifiers | The 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. |
| Provenance | The 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.
{ "type": "funnel", "tier": "puzzle", "outcome": "alt", "funnel": { "started": 2, "early": 0, "done": 2, "missed": 2 }, … }| End | Meaning |
|---|---|
pass | The visitor finished the check. |
closed | They closed the box. |
left | They left the page with the box open. |
alt | They switched from the puzzle to the hold. |
offline | The 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
| Report | What it answers |
|---|---|
| Weekly report | Traffic 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 timelines | Every 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 verify | A 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 funnel | Both 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:
| Metric | Labels | Meaning |
|---|---|---|
otcaptcha_load_total | result, origin | Challenges issued, or refused for an unknown key. |
otcaptcha_verify_total | result, origin | Verifications by outcome; a refusal carries its reason as the result. |
otcaptcha_validate_total | result, code | Server checks decided, success or fail by code. |
otcaptcha_validate_5xx_total | reason | Server checks that could not be decided: store, overload or slow body. Alert on any rise. |
otcaptcha_validate_refused_total | Server checks from an address outside the allow-list. | |
otcaptcha_offline_token_total | Offline passes refused: browsers that could not reach the public listener while your server could. | |
otcaptcha_solve_ms | Histogram of solve times reported by browsers. | |
otcaptcha_solve_engine_total | engine | Solves in WebAssembly, JavaScript workers or on the main thread. |
otcaptcha_risk_signal_total, otcaptcha_risk_measured_total | signal | Checks that fired and counted, and checks that fired and were only measured. |
otcaptcha_attack_level_changes_total | Automatic level changes. Each one is also logged. | |
otcaptcha_funnel_total, otcaptcha_funnel_refused_total | tier, end / reason | Box ends by tier and outcome; beacons refused as malformed or rate-limited. |
otcaptcha_puzzle_total, otcaptcha_puzzle_trace_total | result / shape | Puzzles solved or missed; drag trace shapes. |
otcaptcha_store_errors_total | op | Store failures by operation. Alert on any rise. |