DEV Community

Vix
Vix

Posted on

Detecting VPNs and proxies with IP data — what actually works

Detecting VPNs and proxies with IP data — what actually works

VPN and proxy detection comes up constantly in fraud prevention, content licensing, and abuse mitigation discussions, and it's one of the most oversold capabilities in the IP data space. This article covers what IP-based detection can actually tell you, what it can't, and how to build detection logic that doesn't waste effort chasing false confidence.


What "VPN detection" actually means

There's no definitive signal that says "this connection is a VPN." What exists is a set of indicators that correlate with VPN/proxy usage, each with real false-positive and false-negative rates. Good detection combines several of these signals and produces a confidence level, not a yes/no answer.

The indicators, roughly in order of reliability:

  1. Known VPN/hosting provider ASNs — the IP belongs to an organization that's a VPN provider or a datacenter, not a residential/mobile ISP
  2. Datacenter hosting ranges — even without VPN-specific labeling, an IP registered to AWS, DigitalOcean, OVH, etc. is not a home user
  3. Behavioral signals — port scanning patterns, unusual request timing, shared IP with many simultaneous sessions
  4. Commercial VPN detection databases — curated lists mapping known VPN exit nodes (these require paid subscriptions and go stale quickly as providers rotate IPs)

For most applications without a paid detection service, you're working primarily with #1 and #2 — ASN and organization data.


Building basic detection with ASN/ISP data

IPPubblico.org returns the ISP name and ASN for any IP, which is the foundation for this kind of check:

curl "https://ippubblico.org/?api=1"
Enter fullscreen mode Exit fullscreen mode
{
  "status": "ok",
  "ip": "203.0.113.42",
  "isp": "NordVPN",
  "asn": "AS205016",
  "geo": { "country": "Netherlands", "country_code": "NL" }
}
Enter fullscreen mode Exit fullscreen mode
import requests

KNOWN_VPN_KEYWORDS = [
    'vpn', 'nordvpn', 'expressvpn', 'surfshark', 'privateinternetaccess',
    'protonvpn', 'cyberghost', 'mullvad', 'tunnelbear', 'ipvanish',
    'windscribe', 'hidemyass', 'purevpn',
]

KNOWN_DATACENTER_KEYWORDS = [
    'amazon', 'aws', 'google cloud', 'microsoft azure', 'digitalocean',
    'ovh', 'hetzner', 'linode', 'vultr', 'scaleway', 'oracle cloud',
    'alibaba cloud', 'tencent cloud',
]

def check_ip_type(ip: str = None) -> dict:
    url = 'https://ippubblico.org/?api=1'
    if ip:
        url += f'&ip={ip}'

    data = requests.get(url, timeout=5).json()
    isp = data.get('isp', '').lower()

    is_known_vpn = any(kw in isp for kw in KNOWN_VPN_KEYWORDS)
    is_datacenter = any(kw in isp for kw in KNOWN_DATACENTER_KEYWORDS)

    return {
        'ip': data.get('ip'),
        'isp': data.get('isp'),
        'is_known_vpn_provider': is_known_vpn,
        'is_datacenter': is_datacenter,
        'confidence': 'high' if is_known_vpn else ('medium' if is_datacenter else 'low'),
    }
Enter fullscreen mode Exit fullscreen mode

This catches the obvious cases — someone using a well-known commercial VPN service, or traffic originating from a cloud server rather than a residential connection. It will miss VPN providers using residential IP pools (a growing and deliberately harder-to-detect category) and won't catch anyone running their own VPN on a home connection.


What this approach cannot detect

Be explicit about the limitations, both to yourself and in any documentation for whoever uses this logic downstream:

Residential proxy networks — services that route traffic through real residential IPs (often via consent-based apps or, less legitimately, compromised devices) are specifically designed to look identical to genuine home users. ASN-based detection has no signal here at all; the ISP genuinely is a residential provider.

Self-hosted VPNs — someone running their own WireGuard/OpenVPN server on a rented VPS will show up as "datacenter IP" (medium confidence) but with no way to distinguish "this person runs a personal VPN" from "this person runs a legitimate cloud service that happens to make API calls."

New or small VPN providers — any keyword-matching list is only as good as its maintenance. New providers, white-label VPN services, and rebranded resellers won't match known keywords until someone updates the list.

Mobile carrier NAT — as covered in earlier articles, CGNAT means many genuine users share IPs with carrier infrastructure that can superficially resemble proxy-like shared-IP patterns.


A more complete detection function

Combining multiple signals into a single confidence score, rather than a binary flag:

import requests

def assess_connection_risk(ip: str = None) -> dict:
    url = 'https://ippubblico.org/?api=1'
    if ip:
        url += f'&ip={ip}'

    data = requests.get(url, timeout=5).json()
    isp = data.get('isp', '').lower()
    asn = data.get('asn', '')

    signals = []

    if any(kw in isp for kw in KNOWN_VPN_KEYWORDS):
        signals.append(('known_vpn_provider', 40))
    if any(kw in isp for kw in KNOWN_DATACENTER_KEYWORDS):
        signals.append(('datacenter_hosting', 25))
    if 'hosting' in isp or 'server' in isp or 'colo' in isp:
        signals.append(('generic_hosting_keyword', 15))

    risk_score = sum(weight for _, weight in signals)
    risk_score = min(risk_score, 100)

    return {
        'ip': data.get('ip'),
        'isp': data.get('isp'),
        'asn': asn,
        'signals_triggered': [name for name, _ in signals],
        'risk_score': risk_score,
        'recommendation': (
            'block' if risk_score >= 60 else
            'flag_for_review' if risk_score >= 25 else
            'allow'
        ),
    }
Enter fullscreen mode Exit fullscreen mode

The scoring weights here are illustrative, not authoritative — calibrate them against your own false-positive tolerance. A payment fraud system might weight datacenter detection heavily; a content licensing check might only care about known commercial VPN providers.


Where this fits in a larger system

IP-based VPN/proxy detection should never be the sole gate for any consequential decision. Reasonable places to use it:

  • One signal among several in a fraud score, combined with account history, payment method verification, behavioral analysis
  • Soft friction, not hard blocking — an extra verification step (CAPTCHA, email confirmation) rather than an outright block
  • Logging and monitoring — flagging sessions for review without acting on them automatically
  • Rate limiting adjustments — datacenter/VPN traffic might reasonably get a stricter rate limit without being blocked outright

Where it becomes a problem: using ASN-based VPN detection as a hard, silent block for account creation, checkout, or content access. This guarantees false positives against legitimate VPN users (a large and growing population using VPNs for entirely mundane privacy reasons) and does nothing against the residential-proxy services actively built to evade exactly this kind of check.


Testing your own detection logic

Before deploying VPN detection logic, test it against IPs you know the ground truth for — connect through a VPN yourself and check what the API returns:

# Connect via VPN, then check what IPPubblico sees
curl "https://ippubblico.org/?api=1" | python3 -m json.tool
Enter fullscreen mode Exit fullscreen mode

Compare the isp and asn fields against what you'd expect. This is also a good way to verify that your own detection keyword list actually matches real-world ISP name formatting, which varies more than you'd expect ("NordVPN S.A." vs "NORDVPN" vs "M247 Ltd (NordVPN)" are all things you might see for the same provider).


Quick reference

Signal Reliability Catches
Known VPN provider keyword match High confidence, low coverage Major commercial VPN services only
Datacenter/cloud ASN Medium confidence Any non-residential hosting, including legitimate use
Residential proxy networks Not detectable via ASN Nothing — indistinguishable from real residential
Self-hosted VPN on a VPS Appears as generic datacenter Cannot distinguish from other cloud traffic

Conclusion

ASN and ISP data from a service like IPPubblico gives you a real, useful signal for VPN/proxy detection — but it's a signal with clear and specific blind spots, not a definitive check. The organizations actively trying to evade detection (residential proxy networks in particular) are specifically engineered to defeat exactly this method. Use it as one input in a broader risk assessment, weight it honestly against its real false-positive and false-negative rates, and never let it alone make a hard blocking decision.

Full documentation: ippubblico.org/docs.html
Try it yourself: ippubblico.org


Built VPN detection into a production system? Curious what false-positive rate you settled for as acceptable.

Top comments (0)