glassprint · Concepts

The verdict

glassprint does not hand you a bare id and a number. It returns a typed class— one of four — alongside the id, the confidence, and the additive signals. The class is purpose-built for the AI-agent era: it distinguishes a real person from a declared agent, from undeclared automation, from "we don't know."

The four classes

classWhat it meansHow it is reached
humanA real person, above the confidence floor.Output of the automation classifier when no human-implausible picture is present.
declared_agentAn agent that authenticated itself.Set iff Web Bot Auth (RFC 9421 Ed25519 HTTP Message Signature) verifies at the HTTP layer. Authenticated ≠ trusted — the agent is still scored.
undeclared_automationAutomation hiding as a human.Output of the automation classifier when a human-implausible picture clears the floor and topology allows it.
unknownWe refuse to label.Below the confidence floor, or a single tell, or capped behind a CDN. The honest default.

The confidence floor — it refuses to guess

There is a hard floor (confidenceFloor = 0.6). Below it, the class degrades to unknown rather than a coin-flip label. A lone navigator.webdriver or a lone software GPU resolves to unknown at confidence ~0.4 — which is also how a Tor or resist-fingerprinting user with one tell is protected from a false bot call.

The two-tells rule

A bot verdict is the only thing automation evidence can justify, and it requires a human-implausible picture: ≥2 strong tells, or 1 strong tell plus a second independent tell. The strong tells are navigator.webdriver and a headless user-agent. A software GPU (SwiftShader/llvmpipe/Mesa) is weak on its own — millions of real humans run it — so a lone software-GPU never reaches a verdict.

Bot-eligible confidence is min(0.97, 0.55 + 0.18 × tellCount). We publish population rates with Wilson confidence intervals, not a single "accuracy" number — we tell you where our bullets stop rather than quote a headline you can't reproduce.

Farble suppression — never false-positive a privacy user

Brave and Tor "farble" their canvas and audio — each read returns a slightly different value. The client flags this divergence (two-read detection). When the server sees a farble flag it resolves to a privacy defense, caps the suspect score at 0.2, and blocks the bot verdict — it suppresses suspicion rather than flagging the user as tampered. The one exception is anti-evasion: if the farble claim co-occurs with the webdriver-plus-headless combo, the defense is dropped and farble-claim-with-automation is flagged.

The topology cap

A high-confidence undeclared_automation verdict additionally requires topology === 'direct-edge'. Behind a CDN or an untrusted peer, confidence is capped (cdnConfidenceCap = 0.45) and degrades to unknown. We will not assert automation at high confidence when the network tier could be spoofed.

Web Bot Auth — the declared path

A well-behaved agent can declare itself by signing its request (RFC 9421 Ed25519 HTTP Message Signature, covering @authority + signature-agent with a fresh created). When that verifies, the class is declared_agent. Crucially, authenticated does not mean trusted: the agent is still scored, the class just records the declaration so you can allow good bots without lying about what they are.

Human-review override

A reviewer who confirms a real person (for example by overturning an Art-22 contest) writes a durable-keyed neverAutomation override that downgrades a future undeclared_automation to human. It is keyed on the epoch-stable durable id, so it survives visitorId rotation.

Reading it

branch on the class
const r = await gp.identify({ tag: 'login' });

switch (r.class) {
  case 'human':                 break;                 // proceed
  case 'declared_agent':        allowKnownAgent(r);    // still scored — check r.suspectScore
  case 'undeclared_automation': raiseRisk(r);          // additive risk signal, never an auto-block
  case 'unknown':               break;                 // we refused to guess — fall back to your own rules
}