Skip to main content
ShieldLabs scores every identification from 0 to 100, and the signals array next to the number names every risk signal that produced it. Higher means riskier: more likely masked, spoofed, automated or abusive. Every user, device, visitor and IP address then carries the worst band of its identifications, so one Dangerous signup marks the account. You act on the result in your backend and choose the action for each case: allow, challenge, review or block.

What the Risk Score is

The Risk Score is one value per identification, with the evidence attached.
  • Range 0 to 100. The only value above 100 is 999, the rate-limit marker described under Caveats.
  • Explainable. Every Risk Score ships with a signals array, so you never act on a black box.
  • Delivered, not computed in the browser. It arrives by webhook and is readable from the History API.
Risk signals can add up past 100; the Risk Score you receive is capped at 100.

How the Risk Score is built

Each risk signal that fires adds a fixed weight, and the weights are summed under the combination rules below, then capped at 100. The webhook signals array lists every risk signal that changed the Risk Score as { "name": "<slug>", "weight": <int> }: name is a stable slug (proxy, antidetect_browser) and weight is what it added to the Risk Score. Two details matter when you parse it: a slug can repeat with a partial weight when an earlier result for the same device and IP address is carried forward, and stun_late_correction carries a negative weight when a late network check cancels stun_not_checked. Branch on slugs and detection_flags, and read risk_score for the total. The data object of a webhook for an identification from an anti-detect browser behind a proxy, shortened:
The Risk Score is 70: Anti-detect Browser adds 60 and Proxy adds 10, which places the identification in the Dangerous band. Because both reasons are named, you can see that the anti-detect browser drove this result and choose a different action than you would for a proxy alone. The identification card in the analytics dashboard shows the same Risk Score and weights:
The Risk Score gauge at 70.00, Dangerous, and the Risk signals table of one identification in the analytics dashboard: Anti-detect Browser with weight 60 and Proxy with weight 10.The Risk Score gauge at 70.00, Dangerous, and the Risk signals table of one identification in the analytics dashboard in the dark theme: Anti-detect Browser with weight 60 and Proxy with weight 10.

The Risk Score of one identification and each risk signal with its weight, in the analytics dashboard.

Webhook signals[].name is a stable slug (proxy, antidetect_browser). Branch on name or detection_flags. Display labels can change in the analytics dashboard, and score_details on the History API holds internal descriptions rather than slugs. A numeric weight alone does not tell you which risk signal fired: 30 from os_not_detected is not the same case as 30 from browser_vpn_proxy. Read the band, the flags, the user’s history and the sensitivity of the action together. See Acting on results.

The weights

Every risk signal that adds to the Risk Score carries a fixed weight, published below. This is the scoring contract: each risk signal adds the weight in this table, and the combination rules decide which weights are added. Only two entries differ: a slug carried forward from an earlier result, which can repeat with a partial weight (see above), and the rate_limited entry that comes with the 999 marker (see Caveats). The heavier the weight, the stronger and rarer the tell: Tor or a headless client is a near-certain tell, while a lone VPN or proxy is common and often legitimate, so it carries far less.
The first column is the display label; the second is the slug you receive in signals[].name. Branch on the slug or on detection_flags, and treat score_details on the History API as an internal log: it holds internal descriptions and debug entries, so store it for review but never branch on it or show it to your users. Flag keys match the slugs except for Anti-detect Browser, whose flag is detection_flags.anti_detect_browser; the proxy-routed anti-detect and late network check rows have no flag. The same weight from two different risk signals is not interchangeable. IP Mismatch, Incognito, Search bot, Suspicious Paid Click and Check Incomplete are informational flags with a weight of 0.

How signals combine

The Risk Score is additive, with these rules applied before the sum:
  • Tor and Privacy Relay are exclusive. When either fires, no other network, operating system or anti-detect weight is added next to it. JavaScript Disabled and Browser Automation still add.
  • VPN and Browser VPN/Proxy stand in for the proxy stack. Each replaces the Proxy, Datacenter IP, Abuser Flag, OS Mismatch, OS not Detected, STUN not Checked and Timezone Mismatch weights with its own. Anti-detect Browser still adds on top of a VPN.
  • Anti-detect indicators do not stack. One Anti-detect Browser weight is added, however many indicators fire.
  • Proxy, Datacenter IP and Abuser Flag stack with each other when neither VPN nor Browser VPN/Proxy fires.
  • Known search-engine crawlers score 0. The identification is set to 0 and carries the search_bot flag.
  • JavaScript Disabled (90) on its own places an identification in the Dangerous band.

How to use the Risk Score

The Risk Score maps to three bands. The payload carries only the number (risk_score on the webhook, score in History), with no band field, so map the number to a band in your backend. The recommended action is a guide: pick the action per band that fits your risk tolerance. ShieldLabs returns the Risk Score and every named risk signal on each identification, and detects High-Risk Events on your users. You choose the action for each case (allow, step up, review or block) and act on the result in your backend. ShieldLabs stops fraud and abuse and helps block fraudulent and abusive traffic.

Risk of a user, device, visitor or IP

Only an identification has a number. A user, device, visitor or IP address carries a band: the worst band among its identifications in the period you look at. A user with twenty Trusted identifications and one Dangerous identification is Dangerous, so one masked or automated signup is enough to mark the account. Users, devices, visitors and IPs explains how identifications link to each identity. High-Risk Events are a separate axis. ShieldLabs detects multi-accounting, account sharing, impossible travel and account takeover on your users, each at Medium or High confidence, and a user can be Trusted on every identification and still be detected for multi-accounting. High-Risk Events are available in the analytics dashboard, the API and webhooks. See High-Risk Events. To read an account’s band in your backend, fetch its identifications from the History API and take the highest score, skipping values above 100:
The key reads one domain; page with offset when an account has more than 100 identifications. Search by device_id, visitor_id or ip the same way for a device, a visitor or an address. In the analytics dashboard, every user, device, visitor and public IP card shows this band for the selected period, with the split of its identifications across Trusted, Suspicious and Dangerous (User, device, visitor and IP cards).
The header of the user card for User HID a91f3c7e5b2d4086 in the analytics dashboard: the Dangerous band pill, a red Multi-accounting pill (High confidence) and the band split of 12 identifications: 10 Trusted, 1 Suspicious, 1 Dangerous.The header of the user card for User HID a91f3c7e5b2d4086 in the analytics dashboard in the dark theme: the Dangerous band pill, a red Multi-accounting pill (High confidence) and the band split of 12 identifications: 10 Trusted, 1 Suspicious, 1 Dangerous.

A user in the analytics dashboard: the worst band of its identifications and a High-Risk Event (red pill: High confidence).

Caveats

Read a high Risk Score together with its named risk signals and the user’s history. A real customer on a corporate VPN can reach the Suspicious band; the risk signals show why, and you choose the action for each case. Decide on the Risk Score, its risk signals, the user’s band, any High-Risk Event on the user, and the context (signup, login, payment, withdrawal), never on the number alone. Tune your cut-points gradually as you observe real traffic.
The risk scale is 0 to 100. The value 999 is the rate-limit marker, written when a visitor IP is banned after too many identifications: it is not a 0 to 100 Risk Score and not a band. A rate-limit ban also surfaces as HTTP 429 on the identification request. The 999 marker can arrive in risk_score on the webhook and in score on the History API, so treat any value above 100 as that marker before you read the band. On the webhook the marker comes with one signals entry, { "name": "rate_limited", "weight": 999 }: skip it when you log or sum risk signals.

Next steps

Acting on results

Turn the Risk Score, its risk signals and the user’s band into allow, challenge, review or block in your backend.

Risk Signals

What each risk signal covers, from masking to bots and automation, and how it is surfaced.

Users, devices, visitors and IPs

How each identification links to a user, a device, a visitor and IP addresses, each with its own risk.

Accuracy

How ShieldLabs measures 99.9% identification accuracy and 99.9% risk signal detection accuracy.