Fraud prevention, geo-restriction enforcement, and abuse detection all share a common need: detecting when a user is hiding behind a VPN or proxy.
In this tutorial, you'll build a lightweight VPN/proxy detector in JavaScript using IP geolocation and ASN analysis — no paid threat intelligence feeds required.
How VPN Detection Works
VPN and proxy detection relies on several signals:
- ASN (Autonomous System) analysis — VPN providers use specific hosting companies (DigitalOcean, AWS, OVH, etc.)
- Data center IP detection — Residential users don't connect from data centers
- Geolocation anomalies — Timezone mismatches, impossible travel speeds
- Known VPN provider ranges — Major VPN companies own identifiable IP blocks
We'll combine these signals into a confidence score.
Step 1: Get IP Intelligence
First, grab an API key from Frostbyte (200 free credits, no card required).
async function getIPIntel(ip) {
const API_KEY = 'your-api-key';
const res = await fetch(
`https://api.frostbyte.tools/api/geo/${ip}`,
{ headers: { 'x-api-key': API_KEY } }
);
return res.json();
}
This returns geolocation, ISP, ASN, and organization data — everything we need.
Step 2: Build the VPN Detector
// Known hosting/VPN ASN keywords
const VPN_ASN_KEYWORDS = [
'digitalocean', 'amazon', 'aws', 'google cloud', 'microsoft azure',
'ovh', 'hetzner', 'linode', 'vultr', 'choopa', 'contabo',
'cloudflare', 'akamai', 'fastly', 'leaseweb', 'psychz',
'quadranet', 'cogent', 'zscaler', 'nordvpn', 'expressvpn',
'surfshark', 'mullvad', 'private internet access', 'cyberghost',
'proton', 'hide.me', 'ipvanish', 'tunnelbear', 'windscribe',
'hostwinds', 'servermania', 'hostinger', 'ionos', 'kamatera'
];
// Known datacenter/hosting org keywords
const DATACENTER_KEYWORDS = [
'hosting', 'cloud', 'server', 'data center', 'datacenter',
'vps', 'dedicated', 'colocation', 'colo', 'rack',
'infrastructure', 'network', 'telecom'
];
function analyzeIP(geoData) {
const signals = [];
let score = 0;
const org = (geoData.org || '').toLowerCase();
const isp = (geoData.isp || '').toLowerCase();
const asn = (geoData.as || '').toLowerCase();
// Check 1: Known VPN/hosting ASN
for (const keyword of VPN_ASN_KEYWORDS) {
if (org.includes(keyword) || isp.includes(keyword) || asn.includes(keyword)) {
signals.push(`ASN match: "${keyword}"`);
score += 40;
break;
}
}
// Check 2: Datacenter indicators in org name
for (const keyword of DATACENTER_KEYWORDS) {
if (org.includes(keyword) || isp.includes(keyword)) {
signals.push(`Datacenter indicator: "${keyword}"`);
score += 25;
break;
}
}
// Check 3: Missing or generic ISP (common with VPNs)
if (!geoData.isp || geoData.isp === geoData.org) {
signals.push('ISP matches org (typical of hosting providers)');
score += 10;
}
// Check 4: Country mismatch with timezone (if available)
if (geoData.timezone && geoData.country) {
const tzCountry = geoData.timezone.split('/')[0];
const expectedContinent = getContinent(geoData.countryCode);
if (tzCountry === 'America' && expectedContinent === 'Europe' ||
tzCountry === 'Europe' && expectedContinent === 'America') {
signals.push('Timezone/country continent mismatch');
score += 20;
}
}
// Cap at 100
score = Math.min(score, 100);
return {
ip: geoData.query || geoData.ip,
country: geoData.country,
city: geoData.city,
isp: geoData.isp,
org: geoData.org,
vpnScore: score,
isLikelyVPN: score >= 40,
isPossibleVPN: score >= 20,
signals,
verdict: score >= 40 ? 'LIKELY VPN/PROXY'
: score >= 20 ? 'SUSPICIOUS'
: 'LIKELY RESIDENTIAL'
};
}
function getContinent(countryCode) {
const americas = ['US','CA','MX','BR','AR','CO','CL','PE','VE'];
const europe = ['GB','DE','FR','IT','ES','NL','SE','NO','PL','UA','RO','CH','AT','BE','CZ'];
if (americas.includes(countryCode)) return 'America';
if (europe.includes(countryCode)) return 'Europe';
return 'Other';
}
Step 3: Full Working Script
Here's the complete detection tool you can run right now:
// vpn-detector.js — Run: node vpn-detector.js 1.2.3.4
const API_KEY = process.env.FROSTBYTE_KEY || 'your-api-key';
const API_BASE = 'https://api.frostbyte.tools/api';
const VPN_ASN_KEYWORDS = [
'digitalocean', 'amazon', 'aws', 'google cloud', 'azure',
'ovh', 'hetzner', 'linode', 'vultr', 'choopa', 'contabo',
'cloudflare', 'akamai', 'leaseweb', 'nordvpn', 'expressvpn',
'surfshark', 'mullvad', 'proton', 'ipvanish', 'cyberghost',
'hostwinds', 'hostinger', 'kamatera', 'psychz', 'quadranet'
];
async function detectVPN(ip) {
const res = await fetch(`${API_BASE}/geo/${ip}`, {
headers: { 'x-api-key': API_KEY }
});
const geo = await res.json();
const org = (geo.org || '').toLowerCase();
const isp = (geo.isp || '').toLowerCase();
let score = 0;
const signals = [];
// ASN check
for (const kw of VPN_ASN_KEYWORDS) {
if (org.includes(kw) || isp.includes(kw)) {
signals.push(`Known VPN/hosting provider: ${kw}`);
score += 40;
break;
}
}
// Datacenter check
if (/hosting|cloud|server|data.?center|vps|dedicated|colo/i.test(org + isp)) {
signals.push('Datacenter/hosting indicators in ISP name');
score += 25;
}
// Residential ISPs usually have recognizable names
const residentialPatterns = /comcast|verizon|at&t|spectrum|cox|xfinity|bt |virgin|vodafone|orange|telekom|bell |rogers|shaw /i;
if (residentialPatterns.test(isp)) {
signals.push('Known residential ISP detected');
score -= 20;
}
score = Math.max(0, Math.min(score, 100));
console.log(`\n IP: ${ip}`);
console.log(` Location: ${geo.city}, ${geo.regionName}, ${geo.country}`);
console.log(` ISP: ${geo.isp}`);
console.log(` Org: ${geo.org}`);
console.log(` VPN Score: ${score}/100`);
console.log(` Verdict: ${score >= 40 ? 'LIKELY VPN/PROXY' : score >= 20 ? 'SUSPICIOUS' : 'RESIDENTIAL'}`);
if (signals.length) console.log(` Signals: ${signals.join(', ')}`);
}
// Test with multiple IPs
const ips = process.argv.slice(2);
if (ips.length === 0) {
console.log('Usage: node vpn-detector.js <ip1> [ip2] [ip3]');
console.log('Example: node vpn-detector.js 8.8.8.8 1.1.1.1');
process.exit(1);
}
for (const ip of ips) await detectVPN(ip);
Step 4: Use It in Express Middleware
Add VPN detection to your web app as middleware:
async function vpnMiddleware(req, res, next) {
const ip = req.headers['x-forwarded-for']?.split(',')[0] || req.ip;
// Skip private IPs
if (/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|127\.)/.test(ip)) {
req.vpnCheck = { isLikelyVPN: false, score: 0 };
return next();
}
try {
const geo = await fetch(`https://api.frostbyte.tools/api/geo/${ip}`, {
headers: { 'x-api-key': process.env.FROSTBYTE_KEY }
}).then(r => r.json());
const org = (geo.org || '').toLowerCase();
const isp = (geo.isp || '').toLowerCase();
const combined = org + ' ' + isp;
const isHosting = /digitalocean|aws|azure|ovh|hetzner|vultr|linode|contabo|cloudflare/i.test(combined);
const isVPN = /nordvpn|expressvpn|surfshark|mullvad|proton|cyberghost|ipvanish/i.test(combined);
req.vpnCheck = {
isLikelyVPN: isHosting || isVPN,
score: isVPN ? 90 : isHosting ? 60 : 0,
country: geo.country,
isp: geo.isp
};
} catch {
req.vpnCheck = { isLikelyVPN: false, score: 0, error: true };
}
next();
}
// Usage
app.use(vpnMiddleware);
app.post('/api/signup', (req, res) => {
if (req.vpnCheck.isLikelyVPN) {
// Flag for manual review, add CAPTCHA, or block
console.log(`VPN signup attempt from ${req.ip} (${req.vpnCheck.isp})`);
}
// ...continue signup
});
Real-World Applications
| Use Case | Action on VPN Detection |
|---|---|
| Fraud prevention | Flag transaction for manual review |
| Account security | Require 2FA when VPN detected |
| Geo-restricted content | Show "content unavailable" message |
| Pricing pages | Disable regional pricing (prevent abuse) |
| Rate limiting | Apply stricter limits for datacenter IPs |
| Analytics | Separate bot/VPN traffic from real users |
Limitations and Ethics
This approach catches ~70-80% of VPN traffic. It won't detect:
- Residential VPNs that route through real ISPs
- Fresh/unknown VPN providers not in the keyword list
- Tor exit nodes (those need a separate blocklist)
Always give users a path forward — don't silently block. Show a CAPTCHA, ask for phone verification, or explain why access is restricted.
Try It Now
Get a free API key at Frostbyte — 200 credits, no credit card. Each IP lookup uses 1 credit.
The full IP Geolocation API returns 30+ fields including ISP, ASN, organization, timezone, and coordinates — everything you need for VPN detection.
Building fraud prevention or abuse detection? The Frostbyte MCP Server gives AI agents direct access to IP intelligence, DNS lookups, and more.
Top comments (0)