Docs
Risk-score methodology
The GeoQ risk score is deliberately simple and fully documented. There is no machine-learning black box — you can reproduce any score by hand.
The formula
score = min(100, Σ weight(signal) for each triggered signal) Signal weights
| Signal | Weight | Why |
|---|---|---|
is_tor | +45 | Tor exit node — strong anonymisation |
is_proxy | +40 | Open/anonymising proxy (residential-proxy detection in beta) |
is_datacenter | +35 | Hosting / cloud range, not a residential ISP |
is_vpn | +30 | Known commercial VPN range |
is_bot | +25 | Automation / crawler heuristics (beta) |
Levels
| Level | Score range |
|---|---|
low | 0–29 |
medium | 30–59 |
high | 60–100 |
Worked examples
- Datacenter only → 35 →
medium. (reasons: ["is_datacenter"]) - VPN + datacenter → 30 + 35 = 65 →
high. - Tor + datacenter → 45 + 35 = 80 →
high. - Proxy + datacenter + bot → 40 + 35 + 25 = 100 →
high(capped). - No signals → 0 →
low.
Reproduce it yourself
const WEIGHTS = { is_tor: 45, is_proxy: 40, is_datacenter: 35, is_vpn: 30, is_bot: 25 }; function scoreOf(signals) { const reasons = Object.keys(WEIGHTS).filter((k) => signals[k]); const score = Math.min(100, reasons.reduce((s, k) => s + WEIGHTS[k], 0)); const level = score >= 60 ? "high" : score >= 30 ? "medium" : "low"; return { score, level, reasons }; }
Why we publish this
A score you can't explain is a score you can't defend — to your users, your auditors or a regulator. By documenting the formula we let you audit every decision, tune your own thresholds, and avoid relying on GeoQ as the sole basis of an automated decision about a person. See our acceptable use policy and the accuracy benchmark.