Every Fingerly identification doubles as a bot detection API and a VPN detection API. The same call that returns the visitor ID also reports whether the visitor looks automated and whether the connection comes through Tor, a VPN, a proxy or a hosting provider. You read the answer from your backend, on the stored event or in a webhook.
These are signals for your own policy, not verdicts. Fingerly never blocks anyone on its own, and a VPN is not evidence of fraud by itself, which is why you set what each one is worth.
Where the answer is
| What you want to know | Where to read it | Values |
|---|---|---|
| Is the visitor a person, an automation or a crawler? | visitor_kind on the event | human, ai_bot, automation or search_crawler |
| Does the connection come through an anonymising network? | anonymity_network on the event | tor, vpn, proxy or hosting. Omitted for an ordinary connection. |
| Whose network is it? | asn, asn_name and country_code on the event | The autonomous system number, its name and the ISO country |
| Which signals raised the score? | triggers on the event | The signal groups that fired, heaviest first, each with weight and confidence |
| How suspicious is the session overall? | suspect_score and suspect_level | A score, and low, medium or high |
Signal groups for bots and anonymised networks
| Group | Key in `triggers` | Meaning |
|---|---|---|
| Bot | bot | The client is automated, or says it is a bot. |
| Tor exit node | tor | The connection arrives from the Tor network. |
| VPN | vpn | The connection arrives over a VPN. |
| Datacenter proxy | datacenter_proxy | The address belongs to a proxy or a hosting provider rather than a consumer connection. |
| Residential proxy | residential_proxy | Traffic is relayed through someone else's home connection. |
| IP reputation | ip_reputation | The address has a recent history of abuse. |
Each group has a default weight per platform, listed in the signals reference, and you can change them with risk weights. VPN and residential proxy findings can be weighed by how they were recognised or by confidence. The bot group applies to the web. Whether the visitor is a crawler or an AI agent is told by visitor_kind, not by a signal group.
Read it on your server
const event = await fingerly.events.get(requestId)
if (event.visitor_kind === 'automation') return refuse()
if (event.anonymity_network === 'tor') return challenge()
if (event.anonymity_network === 'vpn' && event.suspect_level !== 'low') return challenge()
An event that is not recorded yet comes back as pending, and an identification that could not be scored has no score, which is not a score of 0. See server-side verification before you act on a result.
Get it pushed to you
identification.completed is sent for every identification. visitor.suspect is sent when one reaches the high level, with every signal that fired in triggers, each carrying its signal, its group, its weight and its confidence. Subscribe to it to react to automation or Tor traffic without polling. See webhooks.
What a browser or an app is told
A page or an app can read suspect_score and suspect_level by default, never the signals, and not at all if you hide them on the key. The groups and fields above are told only to your backend and the dashboard, because knowing which check tripped teaches a fraudster what to hide.