Skip to content
IP IPBot
Get Started

Proxy Detection API - VPN, Tor & Proxy Detection

Use explainable signals to flag proxy-like behavior and known threat sources.

IPBot exposes security signals under security. These signals include an overall risk_score plus a human-readable risk_reasons[] list. Treat these as explainable heuristics to power your own policies.

Explainable Detection

Every detection includes human-readable reasons you can audit and act on.

Multiple Signal Types

VPN, proxy, Tor, datacenter, and threat list matches in one response.

Example
curl -s https://api.ipbot.com/8.8.8.8 | jq ‘.security’

See all fields in Response Schema.

Fraudsters and bad actors use VPNs, proxies, and Tor to hide their identity and bypass security controls. According to industry research, ecommerce companies lose $48 billion annually to fraud, with VPN and proxy usage being a key indicator of suspicious activity.

Key statistics on proxy usage in fraud:

  • 75% of ecommerce businesses are increasing fraud prevention budgets
  • Fraudsters manipulate digital fingerprints using VPNs and proxies to bypass restrictions
  • Multiple user accounts accessing a site from the same IP is a strong fraud indicator
  • Orders from IPs in different countries than billing addresses require additional review

The IPBot API returns comprehensive security data:

{
"security": {
"risk_score": 75,
"risk_reasons": ["hosting_provider", "vpn_detected", "datacenter_ip"],
"usage_type": "Hosting",
"is_datacenter": true,
"is_proxy": true,
"threat_level": "Medium",
"threat_lists": ["firehol_level1"]
}
}
FieldDescriptionTypeExample
risk_scoreOverall risk score (0-100)number75
risk_reasonsHuman-readable risk factorsstring[][“vpn_detected”]
usage_typeIP usage classificationstring”Hosting”
is_datacenterWhether IP is from datacenterbooleantrue
is_proxyWhether proxy-like behavior detectedbooleantrue
threat_levelOverall threat assessmentstring”Medium”
threat_listsMatched threat intelligence feedsstring[][“firehol_level1”]

IPBot uses multiple detection methods to identify proxies and VPNs:

Known VPN and proxy providers operate from specific ASNs:

// Example VPN provider ASNs (these are commonly flagged)
const vpnAsns = [
"AS9009", // M247 (common VPN hosting)
"AS62041", // Datacamp
"AS212238", // Datacamp Limited
"AS60068", // CDN77
"AS202422", // G-Core Labs
];

IPBot maintains lists of known VPN provider ASNs and flags connections from these networks.

Legitimate users typically connect from residential ISPs. Connections from datacenters are suspicious:

const data = await fetch("https://api.ipbot.com/").then((r) => r.json());
if (data.security.is_datacenter) {
// Flag for review - datacenter IPs are rarely used by regular users
addFraudFlag("datacenter_connection", {
network: data.network.org,
asn: data.network.asn,
});
}

IPBot checks against the official Tor exit node list:

if (data.security.risk_reasons.includes("tor_exit")) {
// Tor exit nodes are used for anonymous browsing
// May be legitimate privacy use or malicious activity
handleTorConnection(clientIp);
}

IPBot integrates with open threat intelligence sources:

FeedDescription
FireholAggregated IP blocklists for known attackers
Tor ProjectOfficial Tor exit node list
SpamhausSpam and abuse sources
Datacenter ListsCloud and hosting provider IP ranges

Detect suspicious orders before they result in chargebacks:

async function assessOrderRisk(order) {
const data = await fetch(`https://api.ipbot.com/${order.clientIp}`).then(
(r) => r.json(),
);
const riskFactors = [];
let riskScore = 0;
// Proxy/VPN detection
if (data.security.is_proxy) {
riskFactors.push("VPN or proxy detected");
riskScore += 30;
}
// Datacenter IP
if (data.security.is_datacenter) {
riskFactors.push("Datacenter IP");
riskScore += 25;
}
// Tor exit node
if (data.security.risk_reasons.includes("tor_exit")) {
riskFactors.push("Tor exit node");
riskScore += 40;
}
// Location mismatch
if (data.location.country_code !== order.billingCountry) {
riskFactors.push("IP country differs from billing country");
riskScore += 20;
}
// High-risk region
const highRiskCountries = ["NG", "GH", "PK", "BD"];
if (highRiskCountries.includes(data.location.country_code)) {
riskFactors.push("High-fraud region");
riskScore += 15;
}
return {
score: Math.min(riskScore, 100),
factors: riskFactors,
recommendation: riskScore > 50 ? "review" : "approve",
};
}

Prevent fake account creation:

import requests
def validate_registration(client_ip: str, email: str) -> dict:
data = requests.get(f"https://api.ipbot.com/{client_ip}").json()
blocks = []
# Block datacenter registrations (bots)
if data["security"]["is_datacenter"]:
blocks.append("Datacenter IPs cannot register accounts")
# Require additional verification for VPN users
if data["security"]["is_proxy"]:
return {
"allowed": True,
"requires_verification": True,
"reason": "VPN detected - phone verification required"
}
# Block Tor completely for registrations
if "tor_exit" in data["security"]["risk_reasons"]:
blocks.append("Tor connections not allowed for registration")
# Block if on threat lists
if data["security"]["threat_lists"]:
blocks.append(f"IP on threat list: {data['security']['threat_lists']}")
if blocks:
return {"allowed": False, "reasons": blocks}
return {"allowed": True, "requires_verification": False}

Enforce geo-restrictions while detecting bypass attempts:

async function checkContentAccess(clientIp, contentId) {
const data = await fetch(`https://api.ipbot.com/${clientIp}`).then((r) =>
r.json(),
);
const content = await getContentRules(contentId);
// Check if content is available in user's country
const userCountry = data.location.country_code;
if (!content.availableCountries.includes(userCountry)) {
return { allowed: false, reason: "Not available in your region" };
}
// Detect VPN/proxy bypass attempts
if (data.security.is_proxy) {
// User might be trying to bypass geo-restrictions
return {
allowed: false,
reason: "VPN/proxy detected. Disable to access content.",
suggestion: "Connect without VPN to verify your location",
};
}
return { allowed: true };
}

Add friction for suspicious login attempts:

async function assessLoginRisk(userId, clientIp, userAgent) {
const data = await fetch(`https://api.ipbot.com/${clientIp}`).then((r) =>
r.json(),
);
const userHistory = await getUserLoginHistory(userId);
let riskLevel = "low";
const challenges = [];
// New location
if (!userHistory.countries.includes(data.location.country_code)) {
riskLevel = "medium";
challenges.push("new_location");
}
// VPN when user doesn't normally use VPN
if (data.security.is_proxy && !userHistory.usesVpn) {
riskLevel = "medium";
challenges.push("unexpected_vpn");
}
// Datacenter IP for non-API user
if (data.security.is_datacenter && !userHistory.isApiUser) {
riskLevel = "high";
challenges.push("datacenter_login");
}
// Tor for normal user
if (data.security.risk_reasons.includes("tor_exit")) {
riskLevel = "high";
challenges.push("tor_login");
}
// Determine authentication requirements
if (riskLevel === "high") {
return { action: "block", reason: "Suspicious connection" };
} else if (riskLevel === "medium") {
return { action: "mfa", challenges };
}
return { action: "allow" };
}
interface SecurityInfo {
riskScore: number;
isProxy: boolean;
isDatacenter: boolean;
isTor: boolean;
threatLevel: string;
riskReasons: string[];
}
async function getSecurityInfo(ip?: string): Promise<SecurityInfo> {
const url = ip ? `https://api.ipbot.com/${ip}` : "https://api.ipbot.com/";
const response = await fetch(url);
const data = await response.json();
return {
riskScore: data.security.risk_score,
isProxy: data.security.is_proxy,
isDatacenter: data.security.is_datacenter,
isTor: data.security.risk_reasons.includes("tor_exit"),
threatLevel: data.security.threat_level,
riskReasons: data.security.risk_reasons,
};
}
// Usage
const security = await getSecurityInfo();
if (security.isProxy || security.riskScore > 50) {
requireAdditionalVerification();
}
import requests
from dataclasses import dataclass
from typing import List
@dataclass
class SecurityInfo:
risk_score: int
is_proxy: bool
is_datacenter: bool
is_tor: bool
threat_level: str
risk_reasons: List[str]
threat_lists: List[str]
def get_security_info(ip: str = "") -> SecurityInfo:
url = f"https://api.ipbot.com/{ip}" if ip else "https://api.ipbot.com/"
response = requests.get(url)
data = response.json()
sec = data["security"]
return SecurityInfo(
risk_score=sec["risk_score"],
is_proxy=sec["is_proxy"],
is_datacenter=sec["is_datacenter"],
is_tor="tor_exit" in sec.get("risk_reasons", []),
threat_level=sec["threat_level"],
risk_reasons=sec.get("risk_reasons", []),
threat_lists=sec.get("threat_lists", [])
)
# Usage
security = get_security_info()
if security.is_tor:
block_access("Tor connections not allowed")
elif security.is_proxy and security.risk_score > 50:
require_captcha()
Terminal window
# Get security info for any IP
curl -s https://api.ipbot.com/8.8.8.8 | jq '.security'
# Check if proxy detected
curl -s https://api.ipbot.com/ | jq -r '.security.is_proxy'
# Get risk score
curl -s https://api.ipbot.com/ | jq -r '.security.risk_score'
# Get all risk reasons
curl -s https://api.ipbot.com/8.8.8.8 | jq -r '.security.risk_reasons[]'
# Check threat lists
curl -s https://api.ipbot.com/8.8.8.8 | jq -r '.security.threat_lists[]'
# Combined location and security check
curl -s https://api.ipbot.com/ | jq '{country: .location.country_code, risk: .security.risk_score, proxy: .security.is_proxy}'

Don’t rely solely on proxy detection. Combine with other signals:

async function calculateTotalRisk(clientIp, userAgent, email) {
const ipData = await fetch(`https://api.ipbot.com/${clientIp}`).then((r) =>
r.json(),
);
let totalRisk = 0;
// IP-based signals
totalRisk += ipData.security.risk_score * 0.4;
// Proxy penalty
if (ipData.security.is_proxy) totalRisk += 15;
// Email analysis
if (isDisposableEmail(email)) totalRisk += 20;
if (isRecentlyCreatedDomain(email)) totalRisk += 10;
// Device fingerprinting
const deviceRisk = await getDeviceRiskScore(userAgent);
totalRisk += deviceRisk * 0.2;
// Behavioral analysis
const behaviorRisk = await getBehaviorScore(clientIp);
totalRisk += behaviorRisk * 0.2;
return Math.min(totalRisk, 100);
}

Some legitimate users use VPNs for privacy. Allow them to proceed with verification:

if (security.isProxy && security.riskScore < 50) {
// Low-risk VPN user - allow with friction
return {
action: "verify",
message: "VPN detected. Please verify your identity.",
methods: ["email", "sms"],
};
}

Proxy status can change, but not frequently:

// Cache proxy detection for 1 hour
const CACHE_TTL = 60 * 60 * 1000;
async function getCachedSecurityInfo(ip) {
const cached = cache.get(`security:${ip}`);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const data = await fetch(`https://api.ipbot.com/${ip}`).then((r) => r.json());
cache.set(`security:${ip}`, { data: data.security, timestamp: Date.now() });
return data.security;
}