Real-Time VPN and Proxy Detection
Overview
Detect VPNs, proxies and residential proxies live in the browser, at the moment a user acts. See what the service does and try it on the Real-Time VPN and Proxy Detection product page.
Setup
The script carries no API key. Requests are authorized by origin, so register your domain before your first call.
- Sign up for your IPGeolocation account.
- Add your origin as a Request Origin, for example
https://app.example.com. - Save.
Quick start
<script src="https://static.ipgeolocation.io/web-assets/static/security/session-analysis.js"></script>
<script>
const includeIPSecurity = false;
Analysis
.startMonitoring(includeIPSecurity)
.get()
.then(result => console.log(result))
.catch(error => console.error(error instanceof Error ? error.message : String(error)));
</script>Response for a clean connection:
1{
2 "public_ip": "119.156.x.x",
3 "public_ip_country_code": "PK",
4 "live_vpn_proxy_detection": {
5 "is_anonymous": false,
6 "confidence_score": 100,
7 "proxy_score": 0,
8 "vpn_score": 0
9 },
10 "visitor_actual_location": {
11 "actual_ip": "119.156.x.x",
12 "actual_country_code": "PK",
13 "confidence_score": 100
14 }
15}In plain words: this connection is not anonymized, the service is certain about it, and the visitor is where the request says they are.
Response fields
1. The IP address the request comes from
Two top-level fields, describing the IP address the user appears to be on:
| Field | Type | Meaning |
|---|---|---|
public_ip | string | The IP address your server sees on the request. Behind a VPN or proxy this is the exit node's IP address, not the user's. |
public_ip_country_code | string | Two-letter ISO country code for that IP address. Behind a VPN or proxy, this is the exit node's country, not the user's. |
2. The live verdict: live_vpn_proxy_detection
Four fields, meant to be read together:
| Field | Type | Meaning |
|---|---|---|
is_anonymous | boolean | The headline answer. true means the connection is anonymized through a VPN or a proxy. It does not say which; the two scores below do. |
confidence_score | up to 100 | How much to trust that yes or no. 100 with is_anonymous: false means confidently clean; a low value is weak evidence either way. |
proxy_score | 0 to 100 | Looks like a proxy, including residential and rotating proxies. |
vpn_score | 0 to 100 | Looks like a VPN. |
3. Where the visitor really is: visitor_actual_location
Where the user actually is, recovered by the live tests:
| Field | Type | Meaning |
|---|---|---|
actual_ip | string | The visitor's real IP address behind the VPN or proxy. Falls back to public_ip when nothing is hidden, or when the real IP cannot be detected. |
actual_country_code | string | Two-letter ISO country code of the visitor's actual location. |
confidence_score | up to 100 | Certainty about that actual country. Gate on it before acting on a country mismatch. |
4. What is already known about the IP: ip_security
Present only when includeIPSecurity is true . Every field is documented in the IP Security API response reference.
1{
2 "public_ip": "94.237.x.x",
3 "public_ip_country_code": "DE",
4 "live_vpn_proxy_detection": {
5 "is_anonymous": true,
6 "confidence_score": 90,
7 "proxy_score": 90,
8 "vpn_score": 10
9 },
10 "visitor_actual_location": {
11 "actual_ip": "119.156.x.x",
12 "actual_country_code": "PK",
13 "confidence_score": 80
14 },
15 "ip_security": {
16 "threat_score": 50,
17 "is_tor": false,
18 "is_proxy": true,
19 "proxy_provider_names": [],
20 "proxy_confidence_score": 99,
21 "proxy_last_seen": "",
22 "is_residential_proxy": false,
23 "is_vpn": true,
24 "vpn_provider_names": ["Browsec VPN"],
25 "vpn_confidence_score": 99,
26 "vpn_last_seen": "2026-08-07",
27 "is_relay": false,
28 "relay_provider_name": "",
29 "is_anonymous": false,
30 "is_known_attacker": false,
31 "is_bot": false,
32 "is_spam": false,
33 "is_cloud_provider": true,
34 "cloud_provider_name": "UpCloud Ltd"
35 }
36}Reading it in code:
const liveDetection = result.live_vpn_proxy_detection;
const actualLocation = result.visitor_actual_location;
const ipSecurity = result.ip_security;
liveDetection.confidence_score; // 90
actualLocation.actual_country_code; // "PK"
actualLocation.actual_country_code !== result.public_ip_country_code; // true: presenting DE, actually in PK
ipSecurity.vpn_provider_names; // ["Browsec VPN"]
ipSecurity.threat_score; // 50Acting on the verdict
When is_anonymous is true , confidence_score decides how much friction the session deserves. Blocking everything the service flags costs real customers; ignoring the flag defeats the check. Work in bands, and tune the cutoffs against your own confirmed fraud outcomes:
| confidence_score | What it means | Recommended action |
|---|---|---|
| Below 30 | Very weak signal. Expect false positives. | Allow. Log the result, add nothing to the user's path. |
| 30 to 50 | Uncertain. Could be an unusual network, a mobile carrier, or a corporate gateway. | Allow and monitor. Feed it into your wider risk score; add friction only if another signal agrees. |
| 51 to 80 | Likely anonymized. Enough for friction, not for a hard denial alone. | Challenge. MFA, email or SMS verification, or a CAPTCHA. Hold payouts and first orders for review. |
| 81 and above | Confidently anonymized. | Block or restrict. High proxy_score : block or hold for review. High vpn_score : prefer a hard challenge, since many ordinary people browse through VPNs. |
These bands apply only when is_anonymous is true . High confidence with is_anonymous: false is a clean visitor, not a risky one.
Credits
| Configuration | Credits per call |
|---|---|
includeIPSecurity: false | 3 |
includeIPSecurity: true | 5 |
FAQs
Looking for features, modules, and use cases? Visit the Live Proxy & VPN Detection page.
Explore Live Proxy & VPN Detection