Skip to content
Heedeo

4. The fields to act on

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.

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 verdictWhat it isWhen Heedeo did not answer
flaggedStop this action: flag is true and you have not pressed Trust on the person. data.flagged, the API’s own.false
trusted, blockedYour own label on the person: listed is allow, or block.false
bandallow, 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
noTokenThe 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, visitorIdThe 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, errorThe 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 knowReadNot
whether to stop the actionverdict.flagged, or flagged without the packageflag, decision.flag
the bandverdict.band, or suggested without the packagedecision.band
the scorescoredecision.score, risks[r].score
the flag linethresholds.reviewthreshold
whydecision.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 ReviewIn the packageIn an assistant (MCP)On the wire
Trusttrust(), verdict.trustedlabel_visitor with action: "allow"POST /v1/lists action: "allow"; a later evaluation’s listed: "allow"
Blockblock(), verdict.blockedlabel_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.

{ "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:

FieldWhat it holds
idthe browser’s id
kindstored (this browser itself, known for certain), declared (joined by a shared identity) or matched (joined by a device match)
confidence1 for stored and declared, the match’s confidence for matched
merged_bywhat placed it, in words a support person can read: “this browser”, “same email”, “same account”, “device match 0.95”
evidencethe 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_seenwhen 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:

linkWhat it means
shared_account or shared_emailthe 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_cardthe two presented the same phone or card in evidence.
shared_principalthe two acted for the same person: an agent’s acting_for, or the person’s own browser presenting that account id.
probableHeedeo found one a probable match of the other, not sure enough to make them one visitor; weight is the match’s confidence.
same_machinetwo browsers on one computer, such as an agent’s headless browser beside the person’s own. It never makes the two one visitor.
ipthe two were seen on the same network address recently. A weak link: as often a stranger as the person.

The fields of email:

FieldWhat it holds
disposable, alias_of_existing and patterntrue when disposable_email, alias_of_existing or email_pattern fired
free_providerthe domain is a large free mail provider’s
role_addressthe address names a role, such as admin@, info@ or billing@
young_domainthe reason fired
domain_registeredwhen 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_unknowntrue when the registry was asked and could not say; never a reason
breachHave 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:

FieldWhat it holds
link_weightwhat 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
datacenterthe address belongs to a cloud or hosting provider, not to a home, office or mobile line
vpnthe address is a VPN’s. It can be true where the vpn reason did not fire
vpn_confidencehow sure Heedeo is of vpn: high or medium (below); null unless vpn is true
vpn_servicethe VPN service by name, such as MULLVAD_VPN, when known
residential_proxythe 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_confidencehow sure Heedeo is of residential_proxy: high, medium or low (below); null unless it is true
proxy_servicesthe proxy services seen on the address, such as OXYLABS_PROXY; [] when none
proxy, tor and private_relaythe 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
anonymoustrue when the tor, vpn, proxy or anonymizer reason fired, so false on Private Relay and on mobile networks
network_typeisp, business or hosting
asnthe network’s number, such as AS16509
deviceshow many devices recently used the address. Many means a shared address: an office, a campus, a mobile network or a proxy
riskswhat the address has recently been used for that calls for care, such as TUNNEL, CALLBACK_PROXY or LOGIN_BRUTEFORCE; [] when none
countrythe 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 regionwhere the address is, as named places; never coordinates
timezone_mismatchthe 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:

FieldWhat it holds
tamperedthe browser’s own readings disagree, on the checks behind the browser_tampered reason; null from an older script. tamper lists every disagreement found
tampered_confidencehow sure Heedeo is of tampered: high, medium or low, read as network’s are; null unless it is true
anti_detecttrue 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_machinethe browser runs in a virtual machine, with vm, what showed it
virtual_machine_confidencehow sure Heedeo is of virtual_machine: high or medium; null unless it is true
private_modea private window; null when it cannot be told
rarityhow many of your visitors in the last 30 days have a device that looks like this one; a low number is a rare device
connectionhow 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_frameworktrue 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
interactionhow 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.

ReasonDefaultWhat it means
listed_block100Strong; flags alone. You labelled this visitor, email or network block.
receipt_reused100Strong; 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_email100Strong; flags alone. The address is at a disposable email provider.
no_mx100Strong; 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_existing100Strong; 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_identities100This visitor has used more than one email or account. A person’s own new device brings their identities with it and adds none.
probable_match100This visitor is probably the same person as another of your visitors, who holds other emails or accounts.
related_identities100Another 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_abuse100You 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_action100This 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_browsers80A 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.
datacenter80Abnormal pattern. The address belongs to a cloud provider, not to a home, office or mobile line.
network_burst80Unusually 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_pattern80Unusually many addresses that look generated from one pattern, such as 1001@ and 1002@ at one domain, are arriving. It never flags alone.
domain_burst80Recorded, 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_burst80Recorded, 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_domain80Abnormal pattern. The email’s domain was registered under 30 days ago (Email depth in section 3).
recent_domain50Recorded, 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_burst80Unusually many visitors from one agent operator are arriving at once. It never flags alone.
action_rate80This visitor takes the action much more often than your typical visitor.
declared_agent20An unverified agent claim: the browser says it is an agent and does not prove it.
tor25Privacy network. The network hides the person’s own address.
vpn20Privacy network. The network hides the person’s own address.
proxy20Privacy network. The network hides the person’s own address.
anonymizer20Privacy network. The network hides the person’s own address.
hosting20Privacy network. The address is in a hosting network, as most VPN exits are.
network_changed20Privacy network. The browser was identified from one network and the event came from another.
residential_proxy0Recorded, 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_rate0Recorded, not scored yet. The visitor came from many different addresses in an hour or a day (visitor.addresses).
account_new_browser20A 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_address20Weak 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_seen20Weak tell, breach history on. The address appears in no known data breach, as a newly made address often does.
browser_tampered80Record-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_machine25Weak tell. The browser runs in a virtual machine. Never for a declared or verified agent, whose operator runs it in a cloud.
private_mode10Weak 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_signup50Recorded, 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_change50Recorded, 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).
automation10Weak tell. The browser is automated and does not say it is an agent; an agent that says what it is gets no reason.
voip_phone80Evidence. A non-fixed VoIP or toll-free number.
prepaid_card80Evidence. A prepaid card.
verification_failed40Evidence. A check you ran failed, its kind in the text.
email_unverified20Evidence. Once you have sent email.verified for a day, an address new to the browser that no event verified.
card_mismatch20Evidence. The card’s country is not the country of the event’s address.
relay_email10Evidence. The sign-in provider’s private relay address.
verified_id100Trust, subtracted. A passed id_document or liveness check.
paid_history80Trust. plan paid with paid_since more than 30 days ago and no abuse report.
wallet_card60Trust. Apple Pay, Google Pay, Link or a passed 3-D Secure.
legit_outcome60Trust. You reported the visitor, one of its events or its account as legit.
verified_phone40Trust. A mobile line verified by you or by a passed otp.
card_on_file40Trust. A card that passed its CVC check.
tenure40Trust. An account created more than 90 days ago.
email_tenure20Trust, breach history on. The address was in a breach more than two years ago, so it has existed that long.
no_tokennoteThe 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_expirednoteThe token had expired, so the answer has no visitor facts.
unknown_visitornoteThe token names no visitor of your workspace, so the answer has no visitor facts.
no_identitynoteA 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.