Signal codes
A signup check reports what the signals service
found about the visit in signals.findings and what it could not decide in
signals.not_evaluated. Every entry is a code from this vocabulary, prefixed
fp_ so it can never be confused with a verification’s
reason codes.
"findings": [ { "code": "fp_fast_submission", "class": "binding", "default_raises": true, "detail": { "since_first_token_ms": 812 } }, { "code": "fp_network_vpn", "class": "identity", "default_raises": false }],"not_evaluated": ["fp_novelty_not_evaluated"],"not_evaluated_classes": ["novelty"]What default_raises means
Section titled “What default_raises means”default_raises: true says the default policy treats the finding as worth
asking the person to confirm their email address. It is a default, not a
verdict: no finding says what a person is, and none of them can refuse a
signup. A refusal only ever comes from the email verification.
Emvero follows the default. signal_codes in the answer is every finding with
default_raises: true, in the order the findings came, without repeats, and a
non-empty list moves an allow to allow_with_email_confirmation. Nothing
moves it further, and nothing softens what the email verification answered.
Read default_raises from the finding, not from this page. Each finding
carries its own value, and that is the one Emvero acted on. The tables below
show the same values for reading; code that branches on the finding’s own keeps
working when a code is added.
The three kinds of code:
| Kind | Where it appears | default_raises |
|---|---|---|
| Raising | findings |
true - asks for an email confirmation |
| Reporting | findings |
false - reported, raises nothing |
| Not evaluated | not_evaluated, never in findings |
- |
A code in not_evaluated says something could not be decided, so it is not a
clean result either. not_evaluated_classes lists the classes of those codes,
so you can ask “were the connection’s layers compared at all?” without keeping
a copy of this table.
Classes
Section titled “Classes”Every code lies on exactly one class, and the set of classes is closed. If you write a policy of your own over the findings, write it over classes: it then covers a code added later, which a list of codes silently would not.
| Class | The question it answers |
|---|---|
token |
Was there a token, and could it be read? |
binding |
Does the token belong to this submission - the address, the browser’s self-description, the time between them? |
identity |
What does the network, browser statement or browser probe report, including automation indicators? |
novelty |
How common is this combination of layers in ordinary traffic? |
frequency |
How many other signups look like this one? No code of this class is issued. |
anomaly |
Was there a protocol irregularity, forged probe or browser-property change? |
availability |
Could the signals service look at all? |
Compatibility
Section titled “Compatibility”- A code can be added. Adding one raises
signals.vocabulary_version, so a code you have not seen arrives with a version you have not seen. - A code can be retired. It stops being issued, and its meaning stays written down here.
- A code never changes. Not its meaning, not its class, not its kind, not
its
default_raises, in any version. detailcan gain fields. Skip the ones you do not know.
The vocabulary
Section titled “The vocabulary”Version 10, pinned to Emvero’s internal service source at
revision c53579916601.
Raising: default_raises: true
| Code | Class | Meaning | Issued |
|---|---|---|---|
fp_token_absent | token | No token came with the signup: the field was empty, the script was blocked, the page never asked for one, or the capture node could not issue one. | yes |
fp_token_altered | token | The token failed its integrity check and was not read. | yes |
fp_token_expired | token | The token had expired by the time it was checked. | yes |
fp_token_foreign | token | The token is genuine, but was issued for a page key of another account than the one checking it. | yes |
fp_token_reused | token | This token was already presented in an earlier check on your account, within 70 minutes of being issued. | yes, by Emvero |
fp_fast_submission | binding | The check came sooner after the first token of this page view than a person filling a form takes; `detail.since_first_token_ms` says how soon. | yes |
fp_ip_mismatch | binding | The address that fetched the token and the address that submitted the form differ beyond the comparison prefix. | yes |
fp_ua_mismatch | binding | The browser described itself differently when it fetched the token and when it submitted; `detail.fields` names what differs. | yes |
fp_label_bot | identity | A controlled run labelled a layer of the connection as a bot. | retired |
fp_label_impersonation_tool | identity | A controlled run labelled a layer of the connection as an impersonation tool. | retired |
fp_label_library | identity | A controlled run labelled a layer of the connection as an HTTP library. | retired |
fp_probe_automation | identity | The browser probe found automation indicators, listed in detail.flags. This finding requires email confirmation; it does not establish abuse. | yes |
fp_rule_violation | identity | A consistency rule over the layers fired, or could not be read. | retired |
fp_transport_os_mismatch | identity | The transport layer pointed at a different operating system than the browser claimed. | retired |
fp_combination_unseen | novelty | This combination of connection layers has not been seen in ordinary traffic within the evaluation window. | not in this version |
fp_frequency_domain | frequency | Enough signups within the window used one email domain, popular mail services aside. | retired |
fp_frequency_identity | frequency | Enough signups within the window shared one combination that is rare in ordinary traffic. | retired |
fp_frequency_prefix | frequency | Enough signups within the window came from one network prefix. | retired |
fp_probe_forged | anomaly | The browser probe opened but its build checks were inconsistent. This finding requires email confirmation. | yes |
Reporting: default_raises: false
| Code | Class | Meaning | Issued |
|---|---|---|---|
fp_ip_same | binding | The token was fetched from the same address that submitted the form. | yes |
fp_ip_same_prefix | binding | The two addresses differ but share a comparison prefix (`detail.prefix`: `v4/24` or `v6/64`). | yes |
fp_client_claim_conflict | identity | The User-Agent and the client hints of the same request disagree with each other. | yes |
fp_client_tls_mismatch | identity | The browser engine the User-Agent implies is not the one clients with this TLS handshake usually claim. An app with its own network stack looks the same. | yes |
fp_client_tls_version_mismatch | identity | The claimed Chromium version is older or newer than the handshake it arrived with. An app writing a fresh version over an older system WebView looks the same. | yes |
fp_label_other | identity | A layer carried a label that raises nothing: not from a controlled run, or of another type. | retired |
fp_network_geo_rtt_mismatch | identity | The round trip was too short for the distance the address's location implies. | yes |
fp_network_hosting | identity | The connection that fetched the token came from a hosting network. Reported only: iCloud Private Relay and WARP arrive through such networks. | yes |
fp_network_private_relay | identity | The token's connection came from an iCloud Private Relay egress address. | yes |
fp_network_public_proxy | identity | The token's connection came from an address on a public proxy list. | yes |
fp_network_rtt_gap | identity | The connection's HTTP/2 round trip is much longer than its TCP round trip, the way a connection ending at an intermediary looks. | yes |
fp_network_stack_platform_mismatch | identity | The TCP stack of the connection points at a different operating system than the browser claims. | yes |
fp_network_tor | identity | The token's connection came from a Tor exit. | yes |
fp_network_vpn | identity | The token's connection came from an address on a public VPN list. | yes |
fp_timezone_claim_conflict | identity | The browser's IANA time zone does not match its own UTC offset. | yes |
fp_timezone_offset_mismatch | identity | The browser's UTC offset differs from the offset at the address's location. | yes |
fp_transport_intermediary | identity | The transport layer belonged to a declared intermediary, so its operating system was not compared. | retired |
fp_combination_rare | novelty | The combination has been seen in ordinary traffic, but is not among the common ones. | not in this version |
fp_anomaly | anomaly | The connection that fetched the token had protocol irregularities, listed in `detail.flags`. A signal, not a violation. | yes |
fp_probe_tampering | anomaly | Native browser properties were changed, listed in detail.flags. Informational: browser extensions and page code can also cause this. | yes |
Not evaluated: in not_evaluated
| Code | Class | Meaning | Issued |
|---|---|---|---|
fp_ip_not_comparable | binding | The two addresses are of different families, IPv4 and IPv6, and were not compared. | yes |
fp_ip_not_supplied | binding | Addresses were not compared: no `ip` was sent, it could not be read, or there was no token. | yes |
fp_ua_not_supplied | binding | Self-descriptions were not compared: no `user_agent` was sent, or there was no token. | yes |
fp_client_claims_not_evaluated | identity | The client's claims could not be compared with each other. | yes |
fp_client_tls_not_evaluated | identity | The claimed engine could not be compared with the TLS handshake. | yes |
fp_client_tls_version_not_evaluated | identity | The claimed Chromium version could not be compared with the TLS handshake. | yes |
fp_layer_absent | identity | No findings about the connection's layers could be made: the token carries none. | yes |
fp_layer_unlabelled | identity | No layer of the token carried a label, or labels were not checked. | retired |
fp_network_intelligence_not_evaluated | identity | At least one of the public network lists was unavailable; `network` says which. | yes |
fp_network_measurements_not_evaluated | identity | The connection's network measurements were not available to compare. | yes |
fp_network_not_evaluated | identity | The kind of network the token's connection came from could not be established. | yes |
fp_no_rules | identity | No consistency rules were applied. | retired |
fp_probe_not_evaluated | identity | The browser probe was absent, unreadable, from an unknown or retired build, or could not finish a group of checks. A usable token can still be evaluated. | yes |
fp_timezone_not_evaluated | identity | The browser's time zone was not compared with the address's. | yes |
fp_transport_unavailable | identity | The transport layer's operating system was not compared. | retired |
fp_novelty_not_evaluated | novelty | The current service does not evaluate combination rarity or novelty; the token slots remain unavailable. | yes |
fp_client_part_not_evaluated | availability | The signals service did not evaluate the visit at all. | yes |
fp_version_superseded | availability | The token's layers were computed under a different rules version than the signals service now runs, so they were not compared. | yes |
fp_working_set_unavailable | availability | The set of observations the visit is compared against was not ready. | retired |
Browser-probe limits
Section titled “Browser-probe limits”fp_probe_forged and fp_probe_automation require confirmation when email would
otherwise allow. fp_probe_tampering is informational. Missing or incomplete
probe checks are reported as fp_probe_not_evaluated; a usable token can still
produce an evaluated, billable check. This is different from a whole-service
unavailable result.
Automation indicators do not prove abuse. Some developer tools also trigger the CDP indicator; the rule discounts a detected docked desktop DevTools panel, but a separate DevTools window or mobile remote debugging can still appear.
Connection reports
Section titled “Connection reports”Besides the findings, an evaluated answer carries the node’s comparisons as
reports. Every yes in a report’s checks is also a finding, and every
unavailable is also a not_evaluated code; the reports say which checks ran
and what was not carried. A check is yes, no or unavailable.
| Report | Fields | Check → finding |
|---|---|---|
network |
One entry per public list - vpn, public_proxy, tor, private_relay - each with status (listed, not_listed or unavailable) and, when unavailable, reason (address_unavailable, not_configured, source_unavailable, source_stale, unsupported_address_family); source, fetched_at and source_updated_at name the list |
listed → fp_network_vpn, fp_network_public_proxy, fp_network_tor, fp_network_private_relay |
transport |
rules_version; status - available, not_observed or rules_version_unknown; provenance is not_carried |
stack_platform_mismatch → fp_network_stack_platform_mismatch, rtt_gap → fp_network_rtt_gap, geo_rtt_mismatch → fp_network_geo_rtt_mismatch |
timezone |
browser (source browser_claim) and ip (source geoip), each with status: not_carried - the token carries the outcome, not the zones |
offset_mismatch → fp_timezone_offset_mismatch, claim_conflict → fp_timezone_claim_conflict |
client_claims |
status: available, hints: not_carried; tls.status - match, mismatch, labels_unavailable, unlabeled, no_claim or not_evaluated; tls_version with status (consistent, claim_newer, claim_older, version_unknown, no_claim, unlabeled, labels_unavailable), claimed_version and epoch |
conflict → fp_client_claim_conflict; tls.status: mismatch → fp_client_tls_mismatch; a version mismatch → fp_client_tls_version_mismatch |
probe (v13) |
status - ok, forged, absent, malformed, build_unknown, build_retired or unknown; build |
forged → fp_probe_forged, automation → fp_probe_automation, tampering → fp_probe_tampering |
A report can gain fields; skip the ones you do not know.
Informational notes
Section titled “Informational notes”Since token v13, responses carry signals.notes and signals.notes_version.
Notes are separate from findings: they have no default_raises, do not enter
signal_codes and do not change the default action. Each entry contains code, value,
rules_version and group.
Notes vocabulary 2:
| Code | Group | Values |
|---|---|---|
rtt_extra_leg | path | unavailable, none, far |
webtransport | path | unavailable, not_attempted, unsupported, failed, timeout, ok, refused |
ua_brand | client | unavailable, named, generic_chromium, hints_missing |
bot_claim | client | unavailable, none, crawler_verified, crawler_unverified, crawler_unchecked, tool |
bot_operator | client | unavailable, google, apple, meta, microsoft, yandex, baidu, huawei, openai, anthropic, other |
rtt_extra_leg describes a pattern in TCP, TLS and HTTP/2 timing; webtransport
records the optional session’s outcome; ua_brand describes the browser’s
brand statement. They do not establish that a connection is a proxy or abusive.
bot_claim reports a declared crawler inside its operator’s network
(crawler_verified), outside that network (crawler_unverified), a crawler
with no supported operator check (crawler_unchecked), a declared tool (tool)
or no such claim (none). bot_operator names the declared crawler’s operator.
These are notes, including crawler_unverified: none changes the default action.
none does not establish a human visitor. unavailable means the note could
not be evaluated. There are no repeat-visit counters or farm-cluster notes, and
a declared tool is not currently a raising signal.
Observations in one group can describe the same cause, so do not treat them as
independent proof. Under a newer note vocabulary, an unrecognized value can be
reported as unknown. Neither that value nor unavailable means the whole
signal service was unavailable.