TRACIO analyzes every visitor's IP address server-side. It flags VPNs, proxies, Tor exit nodes, and datacenter origins, and resolves city-level geolocation. All analysis runs server-side with no client-side dependencies.
IP intelligence reaches your application through the webhook payload: the
network object (VPN/proxy/Tor/datacenter booleans plus connection type) and the
geo object (country, city, coordinates, timezone) are delivered on every
webhook. ISP and ASN are added on Business and above. See
Webhooks for the full payload shape and signature verification.
VPN, proxy, Tor, and datacenter classification is resolved from the connecting IP
using commercial IP intelligence databases (IP2Location for VPN/proxy/Tor type,
MaxMind for geolocation and ASN). Each is surfaced as a single boolean on the
webhook network object — there is no per-method breakdown or confidence score in
the public payload.
| Flag | Field | Meaning |
|---|---|---|
| VPN | network.vpn | IP belongs to a known VPN provider |
| Proxy | network.proxy | IP is a datacenter or residential proxy |
| Tor | network.tor | IP is a known Tor exit node |
| Datacenter | network.datacenter | IP belongs to a cloud/hosting provider |
{ "network": { "vpn": true, "proxy": true, "tor": false, "datacenter": false, "connectionType": "VPN" }}// `payload` is the webhook delivery body (/docs/webhooks)if (payload.network.vpn) { // visitor is connecting through a VPN}Datacenter and residential proxies both surface as network.proxy; datacenter
origin is additionally reported as network.datacenter. Classification comes from
the IP2Location proxy database, which covers major cloud/hosting providers (AWS,
Google Cloud, Azure, Oracle Cloud, Alibaba Cloud, DigitalOcean, Hetzner, OVH,
Linode/Akamai, Vultr, and others).
{ "network": { "vpn": false, "proxy": true, "tor": false, "datacenter": true, "connectionType": "DCH" }}A Tor exit-node match on the connecting IP surfaces as network.tor. Separately,
the Tor Browser itself is recognized client-side by its anti-fingerprinting
configuration, independently of the network path — see
Smart Signals.
City-level geolocation is resolved server-side from the connecting IP (MaxMind)
and delivered on the webhook geo object.
| Field | Type | Description | Plan |
|---|---|---|---|
geo.country | string | ISO 3166-1 alpha-2 country code | All |
geo.city | string | City name | All |
geo.lat | number | Approximate latitude | All |
geo.lon | number | Approximate longitude | All |
geo.timezone | string | IANA timezone identifier | All |
{ "geo": { "country": "CZ", "city": "Prague", "lat": 50.05, "lon": 14.4, "timezone": "Europe/Prague" }}On Business and Enterprise plans the carrier is also identified. In the webhook
payload both fields live on the network object:
{ "network": { "vpn": false, "proxy": false, "tor": false, "datacenter": false, "isp": "Comcast Cable", "asn": 7922 }}On a session read from the Server API the split is slightly
different: isp sits on geo and asn on network. Same data, two surfaces —
read the field from where the surface you are using puts it.
On Pro and above the webhook carries a velocity block — how much the visitor has
been moving around recently:
| Field | Type | Description |
|---|---|---|
velocity.events5m | number | Events from this visitor in the last 5 minutes |
velocity.uniqueIps | number | Distinct IPs seen for this visitor |
velocity.uniqueLocations | number | Distinct locations seen for this visitor |
The block is present when the visitor counters are available at event time
(normally the primary phase). A missing block means "no data", not zeros —
don't treat its absence as "no unusual activity".
IP-blocklist matching is not part of the public contract: neither the webhook
payload nor the dashboard exposes blocklist categories. The webhook surface for
network risk is the boolean network flags, the connection type, and the velocity
counters above — use those together with the decision and bot fields (see
Smart Signals) for risk decisions.
This reads the webhook payload's network object directly. See
Webhooks for the full payload and signature verification.
// `payload` is the webhook delivery body (/docs/webhooks)function assessIPRisk(payload: WebhookPayload) { const { vpn, proxy, tor, datacenter } = payload.network
const risks: string[] = [] let riskLevel = "low"
if (tor) { risks.push("Tor exit node") riskLevel = "critical" }
if (vpn) { risks.push("VPN detected") riskLevel = riskLevel === "low" ? "medium" : riskLevel }
if (proxy) { risks.push("Proxy detected") riskLevel = riskLevel === "low" ? "medium" : riskLevel }
if (datacenter) { risks.push("Datacenter IP") riskLevel = riskLevel === "low" ? "medium" : riskLevel }
return { riskLevel, risks }}