# How the check works

> What happens between page load and a verified token, which signals are used, and when a person is asked to act.

A verification is a short conversation between the SDK in the page and
AgentGate. Your server joins at the end, when it redeems the token.

## The flow

1. **Page load.** `AgentGate.init()` (or the declarative widget) starts
   document-wide collectors: counts and timings of key presses (not which
   keys), input events, pointer movement, scrolling and focus, plus browser
   environment facts.
2. **Challenge.** At submit time the SDK asks for a challenge:
   `POST /v1/browser/challenge` with the site key and action. AgentGate
   checks the page's `Origin` against the site's allowed origins and returns
   a challenge ID, a nonce, a proof-of-work difficulty and an
   instrumentation program. A challenge lives five minutes and can be
   verified at most four times.
3. **Work and evidence.** In parallel the browser solves the proof of work
   (a SHA-256 over the nonce with the requested number of leading zero
   bits, 18 by default, in a Web Worker), runs every collector (each capped
   at 800 ms) and answers the instrumentation program, which needs a real
   DOM.
4. **Verify.** `POST /v1/browser/verify` sends the proof and the signals.
   AgentGate labels the request (for example `agentgate:proof:missing`,
   `agentgate:signal:machine_cadence`), runs the site's
   [rule set](/docs/rules-overview) and the human / bot / agent model, and
   answers one of three ways:
   - **verified**: a single-use token (and a clearance, for clearance
     actions);
   - **challenge**: a step-up, described below;
   - **error**: a stable code such as `challenge_failed` or `rate_limited`
     ([error codes](/docs/error-codes)).
5. **Redeem.** The page sends the token with the form; your server redeems
   it with [`POST /v1/siteverify`](/docs/siteverify). That call is the
   enforcement point.

## The step-up check

When the evidence looks unusual the server asks for a step-up instead of
refusing. The SDK then shows the check, inline in the widget or as a modal
dialog:

- **Press and hold** a button until the bar fills (1.2 s by default), with a
  mouse, touch, or Space / Enter held on the focused button. The browser
  also solves a heavier proof of work (20 bits by default).
- **Verify another way**: no pointer, timing or puzzle. The browser does a
  heavier proof of work (three more bits) during a ten-second wait. This is
  the accessible alternative for people who cannot press and hold.

When the operator has configured Private Access Token issuers
(`PRIVATE_TOKEN_ISSUERS_FILE`), the SDK first tries a Private Access Token
redemption (RFC 9577, up to 4 s) and skips the visible check if the
platform attests the device. Whether browsers attach a token to that
cross-origin request has not been verified yet; if none arrives, the check
is shown as usual.

Focus moves into the check and back afterwards, progress is announced to
screen readers, Escape closes the dialog, and nothing animates when the
person prefers reduced motion. Every verification is separate: passing the
check earns one token for that submission.

## What decides

Every decision is a rule-set evaluation:

- **Signal sources** attach labels and scores: proof of work, the
  instrumentation answer, interaction timing, browser environment
  consistency, automation markers (for example CDP or `navigator.webdriver`),
  TLS fingerprints when available, IP intelligence, rate budgets, and
  verified agent identity.
- **Ordered rules** pick `allow`, `challenge`, `block`, `drop` or `count`.
  The built-in rules are the managed groups `agentgate-core@1` and
  `agentgate-agents@1`; operators can add or override rules.
- In [monitor mode](/docs/monitor-and-enforce) the outcome is always allow
  and the would-have decision is recorded.

Each decision is stored with its labels, the matched rule, scores and model
version, so the dashboard can show why a visitor was allowed, challenged or
blocked.

## What it is not

The check raises the cost of automation; it does not prove a person is
present. Everything the browser sends is attacker-controlled: a real
browser driven by a patient script, or recorded human traces replayed, can
pass. AgentGate is designed so that such traffic costs more, is rate-limited,
and is visible in the decision log. See the
[threat model](/docs/threat-model).
