> ## Documentation Index
> Fetch the complete documentation index at: https://heedeo-e1965c.manicule.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For every page in one file, fetch https://heedeo-e1965c.manicule.dev/llms-full.txt (large).
> To search and read these docs as tools, connect the MCP server at https://heedeo-e1965c.manicule.dev/api/mcp.
> Every agent surface: https://heedeo-e1965c.manicule.dev/.well-known/llms-manifest.json

# 4. The fields to act on (/the-fields-to-act-on)

<!-- agent-signals: reading_time_min: 29 · est_tokens: 19331 · updated: 2026-11-11 -->
Related: [Integrating Heedeo](/index.md), [Connect your app](/connect-your-app.md), [1. Quick start](/quick-start.md), [2. Serve Heedeo from your own domain (do this before you go live)](/serve-heedeo-from-your-own-domain.md), [3. One server call: evaluate or log](/one-server-call.md), [5. Decide: score, rules or watch](/decide.md)

## The verdict

With the package, `heedeo.evaluate()` answers a verdict: the answer below in `data`, and the same answer read for you. Read the verdict first, and reach into `data` for a count or a fact.

```ts
const verdict = await heedeo.evaluate({ token, action: "signup", email });

verdict.flagged;                  // stop this action
verdict.trusted;                  // you pressed Trust on this person
verdict.has("vpn", "tor");        // any of these reasons fired
verdict.certain("repeat_action"); // it fired at full strength
verdict.noToken;                  // no usable token: ask for your own verification step
verdict.toLog();                  // one object for your log line
verdict.data;                     // the whole answer, below; null when Heedeo did not answer
```

| On the verdict         | What it is                                                                                                                                                                                                                                                                                                                                                      | When Heedeo did not answer      |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| `flagged`              | Stop this action: `flag` is true and you have not pressed Trust on the person. `data.flagged`, the API's own.                                                                                                                                                                                                                                                   | `false`                         |
| `trusted`, `blocked`   | Your own label on the person: `listed` is `allow`, or `block`.                                                                                                                                                                                                                                                                                                  | `false`                         |
| `band`                 | `allow`, `verify`, `review` or `block` at your thresholds, and `allow` for a person you trust.                                                                                                                                                                                                                                                                  | `null`                          |
| `has(...codes)`        | Any of these reasons fired, at any strength.                                                                                                                                                                                                                                                                                                                    | `false`                         |
| `certain(...codes)`    | Any of these fired at full strength, 100 at Heedeo's defaults whatever weights you set.                                                                                                                                                                                                                                                                         | `false`                         |
| `strength(code)`       | How strongly a reason fired at Heedeo's defaults: 0 when it did not, negative for a trust reason. On a `login` or a name of your own, which Heedeo judges on nothing, it is 0 and `certain()` is false.                                                                                                                                                         | `0`                             |
| `noToken`              | The token was missing, expired, unreadable or names no visitor of yours. False for a person you trust. `data.no_token`, the API's own.                                                                                                                                                                                                                          | `false`                         |
| `eventId`, `visitorId` | The event's id and the person's.                                                                                                                                                                                                                                                                                                                                | `null`                          |
| `toLog()`              | One flat object for a log line: `event_id`, `visitor_id`, `flagged`, `listed`, `band`, `score`, `by` (what decided), `reasons` (their codes), `error` (the error's code, null when Heedeo answered) and `trace_id` (`@heedeo/sdk` 0.2.0-beta.1 or later: the failed call's id for Heedeo support, null when Heedeo answered). It holds no email and no address. | The same, with the error's code |
| `data`, `error`        | The answer below, and why there is none. Exactly one is null.                                                                                                                                                                                                                                                                                                   | `null`, the error               |

Every read is safe when Heedeo did not answer: nothing is flagged, so an outage never refuses anyone, and `error.code` says what happened. `data.flagged` and `data.no_token` are the same reading, made by Heedeo: every answer carries them first, a stored one replayed by `request_id` and a webhook's `event` too, so a caller without the package reads them as they are. The verdict reads them (from `@heedeo/sdk` 0.2.0-beta.1, the first with the verdict), and on an answer from before them reads `flag`, `listed` and the notes the same way. `data.flag` does not know about Trust: it is still true for a flagged person you trust, which is why a rule reads `flagged`. A copy (a spread, JSON) keeps the values, `flagged` among them, and loses the four functions. `verdictOf({ data, error: null })` from `@heedeo/sdk` reads an answer you already hold the same way, such as the `event` of an `event.scored` webhook or an answer in a test.

## Read this, not that

Some facts appear twice in an answer. Read one:

| To know                    | Read                                                | Not                                |
| -------------------------- | --------------------------------------------------- | ---------------------------------- |
| whether to stop the action | `verdict.flagged`, or `flagged` without the package | `flag`, `decision.flag`            |
| the band                   | `verdict.band`, or `suggested` without the package  | `decision.band`                    |
| the score                  | `score`                                             | `decision.score`, `risks[r].score` |
| the flag line              | `thresholds.review`                                 | `threshold`                        |
| why                        | `decision.by`, `decision.risk`, `decision.judged`   |                                    |

The fields under Not stay in every answer, for the code that already reads them. On a workspace still on the legacy verdict, `decision` is a preview of the decision and can disagree with `flag`, so it does not say why: read it as the reason only where `decision.flag` equals `flag`, the check `toLog().by` makes. The same holds for an answer stored while a workspace was legacy.

## Trust and Block, in each place

One label, named four ways. It sits on a person, an email address or a network; Review and an assistant set it on a person or an email address, and a network's comes through the package or `POST /v1/lists`.

| In Review                                                          | In the package               | In an assistant (MCP)                  | On the wire                                                                                                               |
| ------------------------------------------------------------------ | ---------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Trust**                                                          | `trust()`, `verdict.trusted` | `label_visitor` with `action: "allow"` | `POST /v1/lists` `action: "allow"`; a later evaluation's `listed: "allow"`                                                |
| **Block**                                                          | `block()`, `verdict.blocked` | `label_visitor` with `action: "block"` | `POST /v1/lists` `action: "block"`; a later evaluation's `listed: "block"`                                                |
| Press the pressed button again (a person), or **Clear** (an email) | `clearLabel()`               | `label_visitor` with `action: "clear"` | `POST /v1/lists` `op: "remove"`, which answers `removed`; a later evaluation's `listed: null` when no other label matches |

An evaluation's `listed` reads every label that matches it, the person's, the email's and the network's, and a Block wins over a Trust.

A Trust also keeps Auto-confirm (Settings) off the flags it covers, on the person, the email or the network: they are still raised and sent as `flag.created`, and wait in Review for you, unless a Block outweighs the Trust, as in `listed`.

**Dismiss is not Trust.** Dismiss on a flag records the outcome `legit`, as `outcome()`, `resolve_flag` with `dismiss` and `POST /v1/outcomes` do: the person's next events score lower, and `verdict.trusted` stays false. Only a Trust label makes `flagged` false whatever the score.

`trust()`, `block()` and `clearLabel()` need `@heedeo/sdk` 0.2.0-beta.1 or later.

## The answer

The answer to a `signup` that Heedeo flagged: the same person signed up a second time, under another email, from the same browser.

```json
{ "flagged": true,
  "no_token": false,
  "flag": true,
  "score": 150,
  "threshold": 100,
  "thresholds": { "verify": 60, "review": 100, "block": null, "action": null },
  "suggested": "review",
  "decision": { "flag": true, "band": "review", "score": 150, "risk": "account_abuse", "by": "risk", "judged": ["account_abuse"] },
  "risks": { "account_abuse": { "score": 150, "judged": true,
                                "reasons": [{ "code": "repeat_action", "weight": 100 }, { "code": "many_identities", "weight": 50 }] } },
  "version": null,
  "reasons": [{ "code": "repeat_action", "text": "signup already done by this visitor on 7 Nov from this browser", "weight": 100, "base": 100 },
              { "code": "many_identities", "text": "This event raised the visitor's identities to 2; the threshold is 3", "weight": 50, "base": 50 }],
  "visitor": { "id": "613d…", "confidence": 1, "first_seen": "…", "last_seen": "…",
               "emails": { "24h": 2, "7d": 2, "all": 2 }, "accounts": { "24h": 0, "7d": 0, "all": 0 },
               "addresses": { "1h": 1, "24h": 1, "7d": 1 }, "countries": { "1h": 1, "24h": 1, "7d": 1 },
               "browsers": [{ "id": "613d…", "kind": "stored", "confidence": 1, "merged_by": "this browser", "evidence": {}, "first_seen": "…", "last_seen": "…" }],
               "aliases": [],
               "actions": { "signup": { "count": 2, "first": "2026-11-07T18:10:31Z", "last": "…" } } },
  "related": [],
  "account": null,
  "counts": { "24h": 2, "7d": 2 },
  "activity": { "last_hour": 2, "hourly_norm": 0.4, "burst": false },
  "listed": null,
  "email": { "disposable": false, "alias_of_existing": false, "pattern": false, "free_provider": true, "role_address": false,
             "young_domain": false, "domain_registered": null, "domain_age_unknown": false, "breach": null },
  "network": { "link_weight": 0.5, "datacenter": false, "vpn": false, "vpn_confidence": null, "vpn_service": null,
               "residential_proxy": false, "residential_proxy_confidence": null, "proxy_services": [], "proxy": false, "tor": false,
               "private_relay": false, "anonymous": false, "network_type": "isp", "asn": "AS7922", "devices": 3, "risks": [],
               "country": "US", "city": "Boston", "region": "Massachusetts", "timezone_mismatch": false },
  "agent": null,
  "environment": { "tampered": false, "tamper": [], "tampered_confidence": null, "anti_detect": null, "virtual_machine": false, "vm": [],
                   "virtual_machine_confidence": null, "private_mode": false, "rarity": 1, "connection": null,
                   "automation_framework": null, "interaction": { "pointer": 41, "key": 52, "touch": 0 } },
  "event_id": "79c7…" }
```

**`flagged` and `no_token`.** `flagged` is whether to stop this action: `flag`, unless you pressed Trust on the person (`listed: "allow"`). `no_token` is whether the event came with no usable token (a note `no_token`, `token_expired` or `unknown_visitor` in `reasons`), false for a person you trust: ask for your own verification step. Each is derived from the answer when it is sent, so an answer read back later says what it said then.

**`flag` and `decision`.** `flag` is whether the action reached your flag line, or you blocked or reported the person; it does not know about Trust, so read `flagged` to decide. `decision` says why, in the same six fields on every event: `flag`; `band`, which your thresholds under Settings make of `score` (`allow`, `verify`, `review` from the flag line, `block` once you set one); `score`; `risk`, the question that reached your flag line; `by`, what decided: `risk` (Heedeo's answer to that question), `label` (your Block label on the person, their email or their network) `report` (your abuse report on the person or an account they used) or `retry` (a once action tried again by the same person under the email or account of an earlier attempt, which keeps at least that attempt's band until you resolve it as legit), and `null` when nothing flagged; and `judged`, the questions Heedeo judges this action on: `account_abuse` for the once actions of section 3, none for a login or a name of your own. That is Heedeo's rule, read from the action's name; nothing in the call chooses it. A flag can also appear later on an earlier signup, when Heedeo learns that two people are one, and it goes away again (`withdrawn`, section 12) if that turns out wrong.

**`risks`.** What Heedeo answers to each question about the person. There is one today, `account_abuse`: one person making more than one account. Each has its `score`, `judged` (whether Heedeo judges this action on it) and its `reasons`, each with the `weight` it contributed. Every question is scored on every event: on a login, `risks.account_abuse` still says what a signup would have answered, with `judged: false`.

The rest of the decision:

* `score` and `suggested`: the decision's `score` and `band`, at the top level as integrations read them.
* `threshold` and `thresholds`: your flag line and your Verify, Flag and Block lines under Settings, Advanced (60, 100 and none by default). An action can have its own three (Settings, Advanced, Actions): then `thresholds.action` names it.
* `version`: when your weights last changed, or `null` while you use the defaults (Settings, Advanced, Weights; section 9).
* `reasons`: every reason that fired, each with one line of text for you, never for the end user, its `weight`, what it contributed to this action (0 on an action judged on nothing), and `base`, the same at the default weights. Every code, and the four notes that ride in `reasons` with weight 0 (`no_token`, `token_expired`, `unknown_visitor`, `no_identity`), is in the table under Reasons and default weights, below.
* `listed`: your own label for this visitor, email or network: `"block"`, `"allow"` or `null`.

Heedeo enforces nothing: your code reads the answer and decides (section 5).

The visitor (`visitor` is null without a usable token):

* `visitor.id`: the visitor, one id for the person across their browsers, decided by Heedeo on every event: your code stores nothing to group them. An id you stored earlier is the visitor's id or one of its `aliases` (section 7, Merges, has the undo).
* `visitor.confidence`: how sure Heedeo is that every browser in `visitor.browsers` is this person: 1 when it is certain.
* `visitor.first_seen` and `last_seen`: when Heedeo first and last saw the visitor.
* `visitor.browsers`: the person's browsers, the oldest first, each with the fields in the table after this list. A browser of the person is here, not in `related`.
* `visitor.aliases`: the ids a merge retired into this one, the newest first (up to 100). Each still resolves: `GET /v1/visitors/<id>` and `POST /v1/outcomes` with a retired id answer the visitor it joined, with `merged_into` set to its id (section 10), so a customer who stored the old id learns the new one on its next lookup, or at once from a `visitor.merged` webhook (section 12).
* `visitor.actions`: what the visitor did, by action name, across its browsers, this event included: `count`, and the `first` and `last` time. Kept 13 months (section 7).
* `visitor.emails.all` and `visitor.accounts.all`: distinct canonical emails and account ids this visitor has shown you across its browsers, ever (also `24h`, `7d`), this event included. At signup, before a user id exists, emails is the one to use.
* `visitor.addresses` and `visitor.countries`: how many different network addresses and countries this visitor's browsers came from in the last hour, day and week (`1h`, `24h`, `7d`), this event included. Mobile networks, Private Relay and Tor are not counted: many people share them. Home, work and a café are three addresses in a day; many in an hour, or several countries in a day, deserves a look.
* The principal (`acting_for`): the people a declared or verified agent acts for are expected, and do not count as its accounts. An anonymous browser acting for many people is multi-accounting under another name, and they count.

Each browser in `visitor.browsers` has:

| Field                        | What it holds                                                                                                                                                    |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                         | the browser's id                                                                                                                                                 |
| `kind`                       | `stored` (this browser itself, known for certain), `declared` (joined by a shared identity) or `matched` (joined by a device match)                              |
| `confidence`                 | 1 for `stored` and `declared`, the match's confidence for `matched`                                                                                              |
| `merged_by`                  | what placed it, in words a support person can read: "this browser", "same email", "same account", "device match 0.95"                                            |
| `evidence`                   | the same without words: `{}` for the browser itself, the identity's `kind` for a shared one, the match's `score` for a device match, never a hash or a raw value |
| `first_seen` and `last_seen` | when Heedeo first and last saw the browser                                                                                                                       |

Around the visitor:

* `counts`: this browser's events of this action, over `24h` and `7d`.
* `related`: browsers of other visitors related to this visitor's browsers, one entry per link, the strongest first. Each has `visitor_id` (the visitor that browser is in now), `link`, `weight` (how much the link proves, from 0 to 1) and the other browser's own `identities`. The visitor's own browsers are in `visitor.browsers`. `link` is one of the values in the table after this list.
* `account`, when you sent a `user_id`, the facts for a login rule (section 5): `visitors`, the browsers that have presented this account over `24h`, `7d` and `all`, this one included, and `new_browser`, whether this browser is new to it. They are facts for your rule, never a flag. `null` without a `user_id`.
* `email`, what Heedeo read from the address (Email depth, in section 3), with the fields in the table after this list.
* `network`, what Heedeo knows of the event's address, with the fields in the table after this list.
* `agent`, null when nothing says an agent or a program sent the request: `operator` (the operator the agent names or proves), `verified` (it signed with Web Bot Auth, or your edge verified it), `declared` (what its user agent claims), `operator_network` (the address is in an agent operator's network), `automation` (the browser shows automation), `http_client` and `missing_headers`. A headless or automated browser shows in `agent.automation`, and is the `automation` reason only when no agent is declared or verified.
* `agent.http_client`: the HTTP library, tool or crawler the request's user agent names, such as `curl`, `python-requests` or `googlebot`, or `null`. A name means a program, not a person's browser, sent the request.
* `agent.missing_headers`: the headers every browser sends that this request lacked, such as `["accept-language"]`; `[]` when none was missing. `null` when Heedeo cannot tell, as from `@heedeo/sdk` before 0.1.0-pilot.17 or a call without `:forwarded` (section 3). A non-empty list means the request most likely did not come from a person's browser.
* Your own server-to-server calls, your mobile app, and a CDN or proxy in front of your server that does not pass the browser's headers through can show in either field, so check for those before a rule refuses on either. Neither field is a reason; use them in your own rule.
* `environment`, what the identification's browser showed of itself, null without an identification, with the fields in the table after this list.
* `activity`: your traffic for this action in the last hour against its weekly hourly norm, and `burst` when it is well above. It is about your traffic, not this visitor. On a new or quiet account a few test signups are already a burst.

The values of `related[].link`:

| `link`                             | What it means                                                                                                                  |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `shared_account` or `shared_email` | the two presented the same account id or email. An email either of the two only typed, never verified, is a weaker link.       |
| `shared_phone` or `shared_card`    | the two presented the same phone or card in `evidence`.                                                                        |
| `shared_principal`                 | the two acted for the same person: an agent's `acting_for`, or the person's own browser presenting that account id.            |
| `probable`                         | Heedeo found one a probable match of the other, not sure enough to make them one visitor; `weight` is the match's confidence.  |
| `same_machine`                     | two browsers on one computer, such as an agent's headless browser beside the person's own. It never makes the two one visitor. |
| `ip`                               | the two were seen on the same network address recently. A weak link: as often a stranger as the person.                        |

The fields of `email`:

| Field                                           | What it holds                                                                                                                                      |
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `disposable`, `alias_of_existing` and `pattern` | true when `disposable_email`, `alias_of_existing` or `email_pattern` fired                                                                         |
| `free_provider`                                 | the domain is a large free mail provider's                                                                                                         |
| `role_address`                                  | the address names a role, such as `admin@`, `info@` or `billing@`                                                                                  |
| `young_domain`                                  | the reason fired                                                                                                                                   |
| `domain_registered`                             | when the email's domain was registered; `null` for a free provider's, which is never asked, or when the registry could not say                     |
| `domain_age_unknown`                            | true when the registry was asked and could not say; never a reason                                                                                 |
| `breach`                                        | Have I Been Pwned's earliest breach holding the address as `{ "first": "2013-10-04" }`, `first` `null` in none; `null` while breach history is off |

The fields of `network`. A field Heedeo could not learn for this address is `null`:

| Field                              | What it holds                                                                                                                                                                                                              |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `link_weight`                      | what sharing this address proves about two browsers, from 0 to 1. 0 on a mobile network, Private Relay, Tor, an address many devices share and a network Heedeo could not name, where sharing it says nothing              |
| `datacenter`                       | the address belongs to a cloud or hosting provider, not to a home, office or mobile line                                                                                                                                   |
| `vpn`                              | the address is a VPN's. It can be true where the `vpn` reason did not fire                                                                                                                                                 |
| `vpn_confidence`                   | how sure Heedeo is of `vpn`: `high` or `medium` (below); `null` unless `vpn` is true                                                                                                                                       |
| `vpn_service`                      | the VPN service by name, such as `MULLVAD_VPN`, when known                                                                                                                                                                 |
| `residential_proxy`                | the address is on a residential proxy list: proxy traffic has left from it. Most listed addresses are ordinary home or mobile lines with one device lent to a proxy network, so it does not mean this visitor used a proxy |
| `residential_proxy_confidence`     | how sure Heedeo is of `residential_proxy`: `high`, `medium` or `low` (below); `null` unless it is true                                                                                                                     |
| `proxy_services`                   | the proxy services seen on the address, such as `OXYLABS_PROXY`; `[]` when none                                                                                                                                            |
| `proxy`, `tor` and `private_relay` | the address is a proxy, a Tor exit, or Apple's iCloud Private Relay. Private Relay is how many honest Safari users browse, and is never a reason                                                                           |
| `anonymous`                        | true when the `tor`, `vpn`, `proxy` or `anonymizer` reason fired, so false on Private Relay and on mobile networks                                                                                                         |
| `network_type`                     | `isp`, `business` or `hosting`                                                                                                                                                                                             |
| `asn`                              | the network's number, such as `AS16509`                                                                                                                                                                                    |
| `devices`                          | how many devices recently used the address. Many means a shared address: an office, a campus, a mobile network or a proxy                                                                                                  |
| `risks`                            | what the address has recently been used for that calls for care, such as `TUNNEL`, `CALLBACK_PROXY` or `LOGIN_BRUTEFORCE`; `[]` when none                                                                                  |
| `country`                          | the country the address is in, as its ISO 3166-1 alpha-2 code such as `US`: IPinfo's, or your edge's country header (`cf-ipcountry`, `x-vercel-ip-country`) when IPinfo cannot place the address; `null` when neither says |
| `city` and `region`                | where the address is, as named places; never coordinates                                                                                                                                                                   |
| `timezone_mismatch`                | the browser's time zone differs from the address's. A traveller's and a wrong clock differ too, so it is a hint. `null` when either is unknown                                                                             |

A confidence says how far to trust its flag in a rule of your own. Neither `vpn` nor `residential_proxy` is enough to act on alone, at any confidence: count `high` or `medium` beside another sign, and treat `low` as a hint, not enough to refuse anyone (RULES.md).

The fields of `environment`:

| Field                        | What it holds                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tampered`                   | the browser's own readings disagree, on the checks behind the `browser_tampered` reason; `null` from an older script. `tamper` lists every disagreement found                                                                                                                                                                                                                                                                                                                                                                    |
| `tampered_confidence`        | how sure Heedeo is of `tampered`: `high`, `medium` or `low`, read as `network`'s are; `null` unless it is true                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `anti_detect`                | `true` when the browser disguises what it is, the way anti-detect browsers and stealth tools do; `tamper` names what gave it away. Privacy browsers such as Brave and Tor Browser change some readings too, and read `null`. `null` when nothing showed, which does not prove an honest browser; never `false`. A name only this check finds moves no score yet, so `tampered` can be `false` while `anti_detect` is `true`                                                                                                      |
| `virtual_machine`            | the browser runs in a virtual machine, with `vm`, what showed it                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `virtual_machine_confidence` | how sure Heedeo is of `virtual_machine`: `high` or `medium`; `null` unless it is true                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `private_mode`               | a private window; `null` when it cannot be told                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `rarity`                     | how many of your visitors in the last 30 days have a device that looks like this one; a low number is a rare device                                                                                                                                                                                                                                                                                                                                                                                                              |
| `connection`                 | how the browser connected: `tls` (such as `TLSv1.3`), `cipher`, `protocol` (such as `HTTP/2`) and `rtt_ms`, the round trip in milliseconds, each `null` when not known. `null` unless Heedeo is served through the Domains page (through Cloudflare once you apply the Worker's update there), or through the `@heedeo/sdk` proxy running in a Cloudflare Worker. The proxy on Vercel sends only the TLS fingerprint Vercel measures, which Heedeo keeps and does not answer, so there `connection` stays `null`. Moves no score |
| `automation_framework`       | `true` when an automation tool was controlling the browser, or its developer tools were open: a developer testing your site shows here too. `null` when nothing showed either, which does not prove a person was there. Moves no score                                                                                                                                                                                                                                                                                           |
| `interaction`                | how often the person moved or clicked the pointer (`pointer`), pressed a key (`key`) and touched the screen (`touch`) on the page before you called `identify()`, each counted up to 1000; never which keys or where. All three `0` on a signup means nobody used the page: a script sent it, or the form filled and sent itself. An automation tool can type and click as a person does, so counts above `0` do not prove a person. `null` from an older script. Moves no score                                                 |

Testing: test traffic flags. Check what your rule does, not `flag`. Section 5, Test your rule, says what each test signup answers and why local tests score higher than real ones.

## Reasons and default weights

Every reason, with its default as your Settings, Advanced, Weights table shows it before you accept your own. A trust reason speaks for the person and shows negative in `reasons`. A reason whose default is 0 is recorded: it shows in `reasons` wherever it fires, so you can see what it would catch, and decides nothing. A note says something about the call itself and decides nothing. The evidence reasons and how to send their evidence are under Evidence in section 3.

| Reason                | Default | What it means                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| --------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `listed_block`        | 100     | Strong; flags alone. You labelled this visitor, email or network block.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `receipt_reused`      | 100     | Strong; flags alone. A reused token: the code keeps its older name, which rules and weights are keyed by. The token was already spent by an earlier, different event: a replay, answered with `visitor` `null`. The same event sent again gets the first answer back and is not this reason.                                                                                                                                                                                                                                                                                                                                                        |
| `disposable_email`    | 100     | Strong; flags alone. The address is at a disposable email provider.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `no_mx`               | 100     | Strong; flags alone. The email's domain cannot receive mail, so no one reads the address. The honest case is a typo in the domain.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `alias_of_existing`   | 100     | Strong; flags alone. The email is an alias, such as a dot or plus-tag spelling, of an address another of your visitors already holds. The person's own address typed another way (`johndoe@` then `john.doe@`) is never this reason.                                                                                                                                                                                                                                                                                                                                                                                                                |
| `many_identities`     | 100     | This visitor has used more than one email or account. A person's own new device brings their identities with it and adds none.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `probable_match`      | 100     | This visitor is probably the same person as another of your visitors, who holds other emails or accounts.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `related_identities`  | 100     | Another of your visitors, who holds other emails or accounts, is related to this one by a shared account, email, principal, machine or address. It appears only on an event that adds an identity or a new link; `GET /v1/visitors` shows the standing evidence.                                                                                                                                                                                                                                                                                                                                                                                    |
| `confirmed_abuse`     | 100     | You reported this visitor, or an account it has presented or presents now (by `user_id`), as abuse, or a visitor related to this one. Your report on this person flags any action of theirs.                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `repeat_action`       | 100     | This person already did this `signup`, `trial_start`, `redeem:CODE` or `payout` under another email or account; the text says when, and from which browser. Below 100 when Heedeo is likely, not certain, it is the same person.                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `account_browsers`    | 80      | A fact for your login rule (`account.visitors`, section 5), not a sign of abuse: many browsers have presented this account lately, as when a login is shared or sold. It flags nothing on its own.                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `datacenter`          | 80      | Abnormal pattern. The address belongs to a cloud provider, not to a home, office or mobile line.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `network_burst`       | 80      | Unusually many new identities are arriving from this network. An honest person on a network where a farm is signing up is in the same crowd, so it never flags alone.                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `email_pattern`       | 80      | Unusually many addresses that look generated from one pattern, such as `1001@` and `1002@` at one domain, are arriving. It never flags alone.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `domain_burst`        | 80      | Recorded, and weighs 0 on the default weights until it is measured: set its weight under Settings, Advanced, Weights to score it. Unusually many new identities with addresses at one email domain are arriving, against that domain's own hourly norm, as when a farm buys a domain and signs up on it from fresh browsers. A free provider's domain and a disposable one are never counted, and a company's people signing up through the day stay under the norm. It never flags alone.                                                                                                                                                          |
| `device_burst`        | 80      | Recorded, and weighs 0 on the default weights until it is measured: set its weight under Settings, Advanced, Weights to score it. Unusually many new identities are arriving on browsers of one device configuration (platform, engine, screen class, time zone and GPU), against that configuration's own hourly norm, as when a farm signs up from one phone model or one machine under fresh cookies and addresses. It fires on a carrier or Private Relay too, and it never flags alone.                                                                                                                                                        |
| `young_domain`        | 80      | Abnormal pattern. The email's domain was registered under 30 days ago (Email depth in section 3).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `recent_domain`       | 50      | Recorded, and weighs 0 on the default weights until it is measured: set its weight under Settings, Advanced, Weights to score it. The email's domain was registered 30 to 90 days ago (Email depth in section 3).                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `operator_burst`      | 80      | Unusually many visitors from one agent operator are arriving at once. It never flags alone.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `action_rate`         | 80      | This visitor takes the action much more often than your typical visitor.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `declared_agent`      | 20      | An unverified agent claim: the browser says it is an agent and does not prove it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `tor`                 | 25      | Privacy network. The network hides the person's own address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `vpn`                 | 20      | Privacy network. The network hides the person's own address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `proxy`               | 20      | Privacy network. The network hides the person's own address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `anonymizer`          | 20      | Privacy network. The network hides the person's own address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `hosting`             | 20      | Privacy network. The address is in a hosting network, as most VPN exits are.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `network_changed`     | 20      | Privacy network. The browser was identified from one network and the event came from another.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `residential_proxy`   | 0       | Recorded, not scored yet. Privacy network. The address is listed as a residential proxy exit (`network.residential_proxy`): proxy traffic has left from it, which does not mean this visitor used a proxy. Most listed addresses are ordinary home and mobile lines.                                                                                                                                                                                                                                                                                                                                                                                |
| `address_rate`        | 0       | Recorded, not scored yet. The visitor came from many different addresses in an hour or a day (`visitor.addresses`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `account_new_browser` | 20      | A fact for your login rule (`account.new_browser`, section 5), not a sign of abuse: this browser is new to an account another browser already presented. It flags nothing on its own.                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `role_address`        | 20      | Weak tell, signups only. A signup with a role address (`admin@`, `info@`, `billing@`, `support@`, `sales@` and the like) rather than a person's. Never for a declared or verified agent.                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `email_never_seen`    | 20      | Weak tell, breach history on. The address appears in no known data breach, as a newly made address often does.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `browser_tampered`    | 80      | Record-only: reported at weight 0 until you turn its scoring on under Settings, Advanced, Weights (we suggest watching it for two weeks first). The browser misreports what it is; `environment.tamper` names what disagreed. Only the checks behind `tampered` count; a name only `anti_detect` finds moves no score.                                                                                                                                                                                                                                                                                                                              |
| `virtual_machine`     | 25      | Weak tell. The browser runs in a virtual machine. Never for a declared or verified agent, whose operator runs it in a cloud.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `private_mode`        | 10      | Weak tell, with a new identity only. A private window added a new email or account; a private window alone is ordinary, and says nothing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `private_signup`      | 50      | Recorded, and weighs 0 on the default weights until it is measured: set its weight under Settings, Advanced, Weights to score it. A `signup`, `trial_start`, `redeem:CODE` or `payout` came from a private window under a new email or account. With `private_mode` it reaches the default Verify line (60), never Flag: ask for a check your app already has. It never flags alone.                                                                                                                                                                                                                                                                |
| `language_change`     | 50      | Recorded, and weighs 0 on the default weights until it is measured: set its weight under Settings, Advanced, Weights to score it. A `signup`, `trial_start`, `redeem` (bare or `redeem:CODE`) or `payout` under a new email or account, on a home or office line, from a browser that matches one that did one of those on the same address in the last day under another email or account, except for its language or locale: one person changing the browser's language per account. Never a merge, and never a flag alone. Counts once with the identity reasons (`many_identities`, `probable_match`, `related_identities`, `confirmed_abuse`). |
| `automation`          | 10      | Weak tell. The browser is automated and does not say it is an agent; an agent that says what it is gets no reason.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `voip_phone`          | 80      | Evidence. A non-fixed VoIP or toll-free number.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `prepaid_card`        | 80      | Evidence. A prepaid card.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `verification_failed` | 40      | Evidence. A check you ran failed, its kind in the text.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `email_unverified`    | 20      | Evidence. Once you have sent `email.verified` for a day, an address new to the browser that no event verified.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `card_mismatch`       | 20      | Evidence. The card's country is not the country of the event's address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `relay_email`         | 10      | Evidence. The sign-in provider's private relay address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `verified_id`         | 100     | Trust, subtracted. A passed `id_document` or `liveness` check.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `paid_history`        | 80      | Trust. `plan` `paid` with `paid_since` more than 30 days ago and no abuse report.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `wallet_card`         | 60      | Trust. Apple Pay, Google Pay, Link or a passed 3-D Secure.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `legit_outcome`       | 60      | Trust. You reported the visitor, one of its events or its account as legit.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `verified_phone`      | 40      | Trust. A mobile line verified by you or by a passed `otp`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `card_on_file`        | 40      | Trust. A card that passed its CVC check.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `tenure`              | 40      | Trust. An account created more than 90 days ago.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `email_tenure`        | 20      | Trust, breach history on. The address was in a breach more than two years ago, so it has existed that long.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `no_token`            | note    | The event came with no token, so the answer has no visitor or browser facts. It weighs nothing: the email, network and label reasons still apply; the bursts and rates, which count visitors, do not.                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `token_expired`       | note    | The token had expired, so the answer has no visitor facts.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `unknown_visitor`     | note    | The token names no visitor of your workspace, so the answer has no visitor facts.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `no_identity`         | note    | A `signup`, `trial_start`, `redeem:CODE` or `payout` came with neither `email` nor `user_id`, so Heedeo could not count the person's accounts. Send one.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
