If you want to detect a VPN by IP address, the core technique is simple: check whether the address belongs to a known VPN provider's ranges, and check who operates the network the address comes from. Trying to detect a VPN by IP address is not magic or packet inspection - it is data work, and once you understand where the data comes from you can also judge how far to trust it. This post explains how VPN, proxy, and datacenter detection actually works, where it fails, and how to use the is_vpn and is_datacenter flags in The IP API to build a policy that does not punish legitimate users.
How to detect a VPN by IP address: where the data comes from
Every commercial VPN service has to run exit servers somewhere. Those servers have public IP addresses, and those addresses are not random - they are rented from hosting providers, announced in BGP by a known autonomous system, and often reused for months or years. Detection databases are built by collecting these ranges:
- Known provider ranges. VPN operators publish server lists, sell access that can be probed, and concentrate their exits in a relatively small set of network prefixes. Aggregating these observations gives you a list of ranges where the answer to "is this a VPN exit?" is yes with high confidence.
- Datacenter and hosting ranges. Cloud and hosting providers register their address space with the regional internet registries, so a well-maintained dataset knows that an address belongs to a hosting company rather than a consumer ISP. Nearly every VPN exit and every proxy server lives inside one of these ranges, because that is where you rent servers.
- ASN ownership. Every routable address is announced by an autonomous system, and the AS is registered to a specific organization. If you have not met ASNs before, our What Is ASN, Anyway? explainer covers the basics.
The datacenter signal is the workhorse here. Ordinary users browse from ISP and mobile networks; they do not browse from a rack in a hosting facility. So an address that belongs to hosting space is, by itself, strong evidence that the "user" is actually a server: a VPN exit, a proxy, a scraper, or an automated client.
The ASN signal is the strong tell
The single most useful question you can ask about an incoming IP is: what kind of organization announces it? A request that claims to be a person shopping from their living room, arriving from an ASN registered to a cloud or hosting company, is a strong tell. Real residential traffic comes from ASNs owned by consumer ISPs and mobile carriers; traffic from hosting ASNs is servers talking to you.
You can check this by hand with our free IP to ASN tool - paste an address and see which AS announces it and who owns that AS. Do this for a few addresses from your own logs and the pattern becomes obvious quickly: your human users cluster on a handful of local ISPs, and your automated traffic clusters on a handful of hosting networks. When you are ready to act on that pattern, Blocking Bot and Datacenter Traffic by ASN walks through the full log, aggregate, decide workflow.
Be honest about the limits
No detection method is perfect, and anyone selling you 100% accuracy is overselling. Two failure modes matter in practice:
- False negatives: residential proxies. These route traffic through real consumer connections - sometimes through SDKs bundled into free apps, sometimes through outright malware. The exit IP genuinely belongs to a residential ISP, so both the datacenter check and the ASN check pass. Residential proxies are hard for every vendor in this space, full stop. Signals other than the IP (velocity, session behavior, device fingerprints) are how fraud teams catch these, and even then imperfectly.
- False positives: legitimate non-residential traffic. Corporate employees egress through office networks and cloud-hosted security gateways. Privacy-conscious users run VPNs for entirely legitimate reasons. Monitoring services, integrations, and your own customers' backends call you from cloud IPs. A flag that says
is_datacenter: truemeans "this is a server network", not "this is an attacker".
There is also a freshness problem. VPN providers add and rotate exit ranges continuously, and hosting providers acquire new address blocks all the time, so a detection dataset is only as good as its update cycle. A list snapshotted six months ago will miss new exits and keep flagging ranges that have since been reassigned. Whatever data source you use, ask how often it is refreshed before you trust it with enforcement decisions.
The practical conclusion: treat these flags as risk signals to combine with context, not verdicts.
Reading the flags from the API
A single lookup returns geolocation, ASN and company data, and three boolean threat flags: is_vpn, is_datacenter, and is_bogon. The full response format is in the documentation.
curl "https://api.theipapi.com/v1/ip/8.8.8.8?api_key=YOUR_API_KEY"
{
"status": "OK",
"body": {
"ip": "8.8.8.8",
"location": {
"city": "Mountain View",
"country": "United States of America",
"country_code": "US",
"latitude": 37.386,
"longitude": -122.0838,
"region": "California",
"timezone": "America/Los_Angeles"
},
"asn": {
"asn": 15169,
"asn_description": "Google LLC",
"country": "US",
"created": "2005-11-23",
"network": "8.8.8.0/24",
"org_name": "Google LLC",
"rir": "ARIN",
"updated": "2019-10-31"
},
"company": {
"name": "Google LLC",
"address": "1600 Amphitheatre Parkway, Mountain View, CA, US",
"network": "8.8.8.0 - 8.8.8.255",
"route": "8.8.8.0/24"
},
"is_bogon": false,
"is_datacenter": true,
"is_vpn": false
},
"response_time_ms": 10
}
Note how the signals line up: 8.8.8.8 is Google's public DNS resolver, announced by AS15169, and it is correctly flagged is_datacenter: true - it is infrastructure, not a person. Reading the flags in code takes a few lines. Check the JSON status field, because a lookup with no matching record can return HTTP 200 with "status": "Error":
import requests
def ip_risk(ip: str, api_key: str) -> str:
resp = requests.get(
f"https://api.theipapi.com/v1/ip/{ip}",
params={"api_key": api_key},
timeout=5,
)
data = resp.json()
if data.get("status") != "OK":
return "unknown"
body = data["body"]
if body.get("is_vpn"):
return "vpn"
if body.get("is_datacenter"):
return "datacenter"
return "clean"
Batches work too: POST /v1/ip/batch accepts up to 100 IPs per request, which is the right shape for scoring a backlog of signups or an access log - our batch API guide covers the details.
What to do with a positive: three policy tiers
Detection is the easy half. The decision layer is where products differ, and the right policy depends on what a false positive costs you.
- Hard block: streaming, licensing, gambling. If your contracts require enforcing geographic restrictions, a VPN or datacenter exit defeats the geolocation your compliance depends on, and blocking (or forcing an alternate flow) is a defensible default. Users understand why a streaming service rejects VPN exits even when they dislike it.
- Score: fraud and abuse teams. For payments and account security, feed the flags into a score alongside velocity, account age, and order value.
is_datacenter: trueplus a fresh account plus a high-value order is a very different situation fromis_vpn: trueon a three-year-old account with a clean history. Our cybersecurity use case page goes deeper on combining IP intelligence with other signals. - Step-up: most applications. This should be the default for everything else. Millions of people use VPNs for privacy, for public Wi-Fi safety, or because their employer requires it. Hard-blocking them costs you real users. Instead, escalate friction: require email verification, trigger a CAPTCHA, disable the risky action (say, an instant payout) while leaving the rest of the product usable. A step-up is cheap for a legitimate user and expensive for a bot farm.
The pattern to avoid is the lazy one: treating is_vpn as a ban switch across the whole product. That maximizes both missed fraud (residential proxies sail through) and collateral damage (privacy-minded users bounce).
Try it on your own traffic
The fastest way to calibrate is to score real data: take yesterday's signups or a slice of your access log and look at the flag distribution before you enforce anything. Sign up for a free API key - the free tier includes 1,000 requests per day with no card required - and see what your traffic actually looks like.