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 collection of network, anonymity, and threat observations associated with an IP address. Unlike geolocation, it helps answer “what evidence exists and what review action fits this policy?” It cannot prove the identity or intent of a person behind the address.

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.

IPBot emits an evidence-derived 0–100 model score with a band, verdict, reasons, and a versioned Decision result. A score of 0 means that no effective scoring risk remained after evidence, trust, suppression, and rounding; it is not proof that an IP is safe. The number is not a calibrated fraud or abuse probability.

The active model separates risk-direction and trust-direction evidence. Examples include direct threat-list matches, unsuppressed proxy/Tor evidence, stable service identity, verified crawler or public-resolver roles, routability suppression, and source confidence. Risk evidence is fused with a bounded noisy-OR and then damped by applicable trust evidence; it is not linearly added.

Exact weights, floors, suppressions, and policy behavior are versioned implementation details. Use the response’s reasons and model/policy version rather than copying an old point table into application code.

Scores are evidence-derived, not cosmetic, but their granularity cannot exceed the underlying facts. Two IPs with different scoring evidence can 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
Spamhaus ASN-DROPASN-level Spamhaus reputation evidenceEvidence-only
ASN Threat DensityA meaningful share of the ASN’s IPv4 space overlaps threat rangesEvidence-only
Recently Allocated NetworkThe registered allocation date is under 90 days oldEvidence-only
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
Published IPBot outcome benchmarkNot yetProvider-specificProvider-specificProvider-specific
PricingFree tier availableCheck providerCheck providerCheck provider

This is a product-surface comparison, not an accuracy or latency benchmark. Provider packaging and prices change; verify current terms before making a purchasing decision.

Do not reinterpret the model score as a probability or copy a stale threshold table. Start with the API’s versioned decision and keep a fallback for unknown actions:

function applyIPDecision(ipData) {
switch (ipData.decision?.action) {
case "block": return denyRequest();
case "challenge": return requireAdditionalVerification();
case "monitor": return allowAndRecordReviewContext();
case "allow": return allowRequest();
default: return requireManualReview();
}
}

IP reputation is one component of a broader risk system. Combine reasoned decisions and independent business signals at the policy layer; do not average unrelated 0–100 values as if they shared a probability scale:

function reviewContext(ipData, account) {
return {
ipAction: ipData.decision?.action ?? "manual_review",
ipReasons: ipData.decision?.reason_codes ?? [],
newAccount: account.ageDays < 7,
recentCredentialReset: account.recentCredentialReset,
};
}

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 estimates the 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: