Skip to content
IP IPBot
Get Started

IP Reputation API - Risk Scoring and Threat Detection

A reputation signal you can audit: scores come with reasons and threat-list matches.

IPBot’s risk scoring is designed to be explainable. Instead of a black box, responses include evidence.signals[] with labels, severity, and confidence so you can build stable UI and internal policy rules.

Example
curl -s https://api.ipbot.com/v1/ip/8.8.8.8 | jq ‘{score, classification, signals: .evidence.signals}’

Pair this with caching guidance in Rate Limits.

IP reputation is a trust assessment for an IP address based on its historical behavior, network characteristics, and presence on threat intelligence feeds. Unlike simple geolocation that answers “where is this IP?”, reputation scoring answers “should I trust this IP?”

Every IP address accumulates a digital footprint over time. Mail servers that send spam get blacklisted. IPs used for DDoS attacks appear on abuse databases. VPN and proxy services operate from known IP ranges. Datacenters host both legitimate services and malicious infrastructure. IP reputation aggregates these signals into actionable intelligence.

The global IP reputation and fraud detection market reached $3.2 billion in 2024 and is projected to grow at 14.8% CAGR through 2030. This growth is driven by increasing online fraud, regulatory compliance requirements, and the need for real-time risk assessment in digital transactions.

IPBot generates a risk score from 0-100 for every IP address, where 0 indicates minimal risk and 100 indicates maximum risk. Unlike black-box scoring systems, IPBot provides complete transparency about what factors contributed to the score.

Connection Type Analysis (0-30 points)

  • VPN detection: +15 to +25 points depending on the provider
  • Proxy detection: +10 to +20 points based on proxy type
  • Tor exit node: +25 to +30 points (highest anonymization)
  • Residential proxy: +20 points (often used for fraud)

Infrastructure Classification (0-25 points)

  • Datacenter/hosting IP: +5 to +15 points
  • Cloud provider ranges: +5 to +10 points
  • Known bulletproof hosting: +20 to +25 points

Threat Intelligence (0-45 points)

  • Presence on spam blacklists: +5 to +15 points per list
  • Abuse database entries: +10 to +20 points
  • Known malware infrastructure: +15 to +25 points
  • Recent attack source: +10 to +20 points

These factor weights are combined probabilistically (a bounded noisy-OR), not linearly summed — so multiple signals never simply pile up at 100, and the score stays on a smooth, calibrated 0-100 curve.

Scores are calibrated, not cosmetic. Two IPs with different evidence get different scores. Two IPs with identical evidence — for example several public proxies on the same network sharing the same threat-list and proxy-detection signals — correctly receive the same score; IPBot does not manufacture per-IP differences the underlying data cannot support.

Fine-grained per-IP differentiation (continuous proxy fraud scores, proxy recency) depends on enhanced/commercial proxy intelligence. On base data, expect conservative risk classification and bands rather than a unique number for every individual IP.

{
"score": {
"risk_score": 65,
"verdict": "challenge",
"recommended_action": "captcha_challenge"
},
"classification": {
"threat_level": "Medium",
"is_proxy": true,
"is_vpn": true,
"is_tor": false,
"is_datacenter": true,
"is_known_crawler": false,
"confidence": "medium"
},
"evidence": {
"signals": [
{ "category": "privacy", "label": "VPN", "severity": "medium", "confidence": "medium" },
{ "category": "network", "label": "Datacenter", "severity": "low", "confidence": "high" }
]
}
}

Online fraud costs businesses over $48 billion annually. IP reputation provides a critical first-line defense by identifying suspicious connections before transactions complete.

Implementation Pattern:

async function assessTransactionRisk(ip, orderValue) {
const response = await fetch(`https://api.ipbot.com/v1/ip/${ip}`);
const data = await response.json();
const { score, classification, evidence } = data;
const signalLabels = evidence.signals.map((signal) => signal.label);
// High-value transactions from risky IPs require additional verification
if (orderValue > 500 && score.risk_score > 50) {
return {
action: "REQUIRE_VERIFICATION",
reasons: signalLabels,
score: score.risk_score,
};
}
// Block transactions from extremely high-risk IPs
if (score.risk_score > 85) {
return {
action: "BLOCK",
reasons: signalLabels,
score: score.risk_score,
};
}
// VPN users may need additional friction
if (classification.is_vpn && orderValue > 200) {
return {
action: "SOFT_CHALLENGE",
reasons: signalLabels,
score: score.risk_score,
};
}
return { action: "ALLOW", score: score.risk_score };
}

Key Fraud Signals:

  • Mismatch between billing address country and IP geolocation
  • Known proxy or VPN usage during high-value purchases
  • IP associated with previous chargebacks
  • Multiple accounts from same high-risk IP

Email service providers and marketers use IP reputation to validate signups and protect deliverability. Fraudulent signups from disposable email addresses often originate from anonymized connections.

Email Signup Validation:

import requests
def validate_email_signup(ip_address, email):
response = requests.get(f'https://api.ipbot.com/v1/ip/{ip_address}')
data = response.json()
score = data['score']
classification = data['classification']
signal_labels = [signal['label'] for signal in data['evidence']['signals']]
# Flag signups from anonymized connections
if classification['is_tor'] or classification['is_proxy']:
return {
'valid': False,
'reason': 'anonymous_connection',
'action': 'require_phone_verification'
}
# Datacenter IPs often indicate bots
if classification['is_datacenter'] and score['risk_score'] > 40:
return {
'valid': False,
'reason': 'suspected_bot',
'action': 'show_captcha'
}
# Known abuse signals can block signup
if 'Known Abuse' in signal_labels:
return {
'valid': False,
'reason': 'known_abuse',
'action': 'block_signup'
}
return {'valid': True, 'risk_score': score['risk_score']}

IP reputation enhances authentication security by identifying suspicious login attempts before they succeed.

Adaptive Authentication:

async function getAuthenticationLevel(ip, userId) {
const [ipData, userHistory] = await Promise.all([
fetch(`https://api.ipbot.com/v1/ip/${ip}`).then((r) => r.json()),
getUserLoginHistory(userId),
]);
const { score, classification, location, evidence } = ipData;
const signalLabels = evidence.signals.map((signal) => signal.label);
// New location from high-risk IP = maximum friction
const isNewLocation = !userHistory.countries.includes(location.country_code);
if (isNewLocation && score.risk_score > 60) {
return "MFA_REQUIRED_WITH_EMAIL_NOTIFICATION";
}
// VPN from new location = elevated friction
if (isNewLocation && classification.is_vpn) {
return "MFA_REQUIRED";
}
// Known abuse signals = block and notify
if (signalLabels.includes("Known Abuse")) {
return "BLOCK_WITH_ADMIN_ALERT";
}
// High risk score = challenge
if (score.risk_score > 70) {
return "CAPTCHA_REQUIRED";
}
return "STANDARD_AUTH";
}

IP reputation helps distinguish legitimate API consumers from abusive bots and scrapers.

function calculateRateLimit(ipData) {
const { score, classification } = ipData;
// Datacenter IPs get stricter limits
if (classification.is_datacenter) {
return { requestsPerMinute: 10, burstLimit: 20 };
}
// High-risk IPs get minimal access
if (score.risk_score > 70) {
return { requestsPerMinute: 5, burstLimit: 10 };
}
// Proxies get reduced limits
if (classification.is_proxy || classification.is_vpn) {
return { requestsPerMinute: 30, burstLimit: 50 };
}
// Normal residential traffic
return { requestsPerMinute: 60, burstLimit: 100 };
}

IPBot exposes product-level signals instead of raw feed names or internal rule IDs. Each signal has a stable label, category, severity, and confidence so your application can explain decisions without binding to IPBot’s private data pipeline.

Signal LabelDescriptionTypical Impact
VPNTraffic appears to come through a VPN serviceMedium
ProxyTraffic appears to come through a proxy serviceMedium
Tor Exit NodeTraffic appears to exit through the Tor networkHigh
DatacenterIP belongs to hosting or cloud infrastructureLow to medium
Known AbuseIP has abuse or threat evidenceHigh
Residential ProxyResidential-looking network with proxy evidenceMedium to high
Private RelayPrivacy relay traffic, not residential proxyLow to medium
Verified CrawlerSearch or platform crawler verified by IPBotInformational
Terminal window
# Get reputation data for any IP
curl -s https://api.ipbot.com/v1/ip/185.220.101.42 | jq '{score, classification, signals: .evidence.signals}'
# Check specific security fields
curl -s https://api.ipbot.com/v1/ip/185.220.101.42 | jq '{
risk_score: .score.risk_score,
is_vpn: .classification.is_vpn,
signals: [.evidence.signals[].label]
}'
class IPReputationClient {
constructor(baseUrl = "https://api.ipbot.com") {
this.baseUrl = baseUrl;
this.cache = new Map();
this.cacheTTL = 3600000; // 1 hour
}
async getReputation(ip) {
// Check cache first
const cached = this.cache.get(ip);
if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
return cached.data;
}
const response = await fetch(`${this.baseUrl}/v1/ip/${ip}`);
if (!response.ok) {
throw new Error(`Failed to get reputation: ${response.status}`);
}
const data = await response.json();
// Cache the public reputation slice
this.cache.set(ip, {
data: {
score: data.score,
classification: data.classification,
signals: data.evidence.signals,
},
timestamp: Date.now(),
});
return this.cache.get(ip).data;
}
async isHighRisk(ip, threshold = 70) {
const reputation = await this.getReputation(ip);
return reputation.score.risk_score >= threshold;
}
async getThreats(ip) {
const reputation = await this.getReputation(ip);
return {
isVPN: reputation.classification.is_vpn,
isProxy: reputation.classification.is_proxy,
isTor: reputation.classification.is_tor,
signals: reputation.signals.map((signal) => signal.label),
};
}
}
// Usage
const client = new IPReputationClient();
const reputation = await client.getReputation("185.220.101.42");
console.log(`Risk Score: ${reputation.score.risk_score}`);
console.log(`Threat Level: ${reputation.classification.threat_level}`);
console.log(`Signals: ${reputation.signals.map((signal) => signal.label).join(", ")}`);
import requests
from functools import lru_cache
from datetime import datetime, timedelta
class IPReputationClient:
def __init__(self, base_url='https://api.ipbot.com'):
self.base_url = base_url
self._cache = {}
self._cache_ttl = timedelta(hours=1)
def get_reputation(self, ip: str) -> dict:
# Check cache
if ip in self._cache:
cached_data, cached_time = self._cache[ip]
if datetime.now() - cached_time < self._cache_ttl:
return cached_data
response = requests.get(f'{self.base_url}/v1/ip/{ip}')
response.raise_for_status()
data = response.json()
reputation = {
'score': data['score'],
'classification': data['classification'],
'signals': data['evidence']['signals'],
}
# Update cache
self._cache[ip] = (reputation, datetime.now())
return reputation
def is_high_risk(self, ip: str, threshold: int = 70) -> bool:
reputation = self.get_reputation(ip)
return reputation['score']['risk_score'] >= threshold
def get_threat_summary(self, ip: str) -> dict:
reputation = self.get_reputation(ip)
return {
'score': reputation['score']['risk_score'],
'level': reputation['classification']['threat_level'],
'is_anonymous': (
reputation['classification'].get('is_vpn')
or reputation['classification'].get('is_proxy')
or reputation['classification'].get('is_tor')
),
'signals': [signal['label'] for signal in reputation['signals']]
}
# Usage
client = IPReputationClient()
# Check if IP is high risk
if client.is_high_risk('185.220.101.42'):
print('High risk IP detected!')
# Get detailed threat information
threats = client.get_threat_summary('185.220.101.42')
print(f"Risk Score: {threats['score']}")
print(f"Anonymous: {threats['is_anonymous']}")
print(f"Signals: {', '.join(threats['signals'])}")
<?php
class IPReputationClient {
private string $baseUrl;
private array $cache = [];
private int $cacheTTL = 3600;
public function __construct(string $baseUrl = 'https://api.ipbot.com') {
$this->baseUrl = $baseUrl;
}
public function getReputation(string $ip): array {
// Check cache
if (isset($this->cache[$ip])) {
$cached = $this->cache[$ip];
if (time() - $cached['timestamp'] < $this->cacheTTL) {
return $cached['data'];
}
}
$response = file_get_contents("{$this->baseUrl}/v1/ip/{$ip}");
$data = json_decode($response, true);
// Cache result
$reputation = [
'score' => $data['score'],
'classification' => $data['classification'],
'signals' => $data['evidence']['signals']
];
$this->cache[$ip] = [
'data' => $reputation,
'timestamp' => time()
];
return $reputation;
}
public function isHighRisk(string $ip, int $threshold = 70): bool {
$reputation = $this->getReputation($ip);
return $reputation['score']['risk_score'] >= $threshold;
}
}
// Usage
$client = new IPReputationClient();
$reputation = $client->getReputation('185.220.101.42');
echo "Risk Score: " . $reputation['risk_score'] . "\n";
echo "Action: " . $reputation['score']['recommended_action'] . "\n";
FeatureIPBotMaxMind minFraudIPQSSift
Free TierYesNoLimitedNo
API Key RequiredNoYesYesYes
Risk Score0-1000-990-1000-100
Explainable ReasonsYesLimitedYesLimited
VPN DetectionIncludedSeparate productIncludedIncluded
Tor DetectionIncludedSeparate productIncludedIncluded
Abuse SignalsYesYesYesYes
CORS EnabledYesNoYesNo
Response TimeUnder 50msUnder 100msUnder 100msUnder 150ms
PricingFree tier availableFrom $50/moFrom $99/moCustom

Different actions require different thresholds:

const THRESHOLDS = {
BLOCK: 85, // Very high confidence of malicious
REQUIRE_MFA: 60, // Elevated risk, verify identity
SHOW_CAPTCHA: 40, // Moderate risk, prove human
LOG_ONLY: 20, // Low risk, just monitor
};

IP reputation is one component of a comprehensive fraud detection system:

function calculateOverallRisk(ipData, userBehavior, deviceFingerprint) {
const ipRisk = ipData.score.risk_score * 0.3;
const behaviorRisk = userBehavior.anomalyScore * 0.4;
const deviceRisk = deviceFingerprint.riskScore * 0.3;
return ipRisk + behaviorRisk + deviceRisk;
}

Not all VPN users are malicious. Consider context:

function assessVPNRisk(ipData, context) {
if (!ipData.classification.is_vpn) return "low";
// Privacy-conscious users in sensitive contexts
if (context.isPrivacySensitive) return "acceptable";
// High-value transactions from VPNs need verification
if (context.transactionValue > 1000) return "high";
// Account creation from VPN is suspicious
if (context.isNewAccount) return "elevated";
return "moderate";
}

IP reputation changes slowly. Cache for at least 1 hour:

// Recommended cache TTLs
const CACHE_TTL = {
HIGH_RISK: 1800000, // 30 minutes for high-risk IPs
MEDIUM_RISK: 3600000, // 1 hour for medium-risk
LOW_RISK: 86400000, // 24 hours for low-risk
};

What is the difference between IP reputation and IP geolocation?

Section titled “What is the difference between IP reputation and IP geolocation?”

IP geolocation determines the physical location of an IP address (country, city, coordinates). IP reputation assesses the trustworthiness of an IP based on its history and characteristics. Both are useful for different purposes - geolocation for localization and compliance, reputation for security and fraud prevention.

IPBot refreshes its intelligence stack on a regular operations cadence and calculates public risk scores at request time from the latest loaded data.

The IP address itself cannot be spoofed in a TCP connection due to the three-way handshake. However, attackers can use previously unknown IPs or rotate through IP addresses. This is why IP reputation should be one component of a multi-layered security approach.

Not necessarily. Many legitimate users use VPNs for privacy, especially in countries with internet restrictions. Instead of blanket blocking, consider requiring additional verification for high-risk actions from VPN IPs.

Build an appeals process and monitor your block rates. If legitimate users are frequently flagged, adjust your thresholds or add exceptions for specific use cases. Use risk scoring as one input rather than the sole decision factor.

Start using IP reputation scoring in your application:

Terminal window
# Quick test
curl https://api.ipbot.com/v1/ip/185.220.101.42 | jq '{score, classification, signals: .evidence.signals}'

Resources: