IPBot
Get Started
Back to Blog
| Security

IP Intelligence for Fraud Prevention - A Complete Guide for 2026

Learn how to use IP intelligence data including geolocation, risk scoring, and proxy detection to prevent online fraud, account takeover, and payment fraud.

Fraud PreventionSecurityRisk ScoringE-commerce

Online fraud costs businesses over $48 billion annually. As fraudsters become more sophisticated, traditional rule-based systems struggle to keep pace. IP intelligence provides a critical layer of defense by analyzing connection metadata that fraudsters cannot easily hide or spoof.

This guide covers practical techniques for using IP data to detect and prevent fraud across authentication, payments, and account management workflows.

Understanding IP-Based Fraud Signals

Every internet connection carries metadata that reveals valuable context about the user. IP intelligence transforms raw IP addresses into actionable risk signals.

Core Fraud Indicators

Geographic Anomalies

  • Billing address in New York, IP geolocation in Lagos
  • Account registration from one country, login from another within minutes
  • Transactions from countries where you have no legitimate customers

Anonymization Signals

  • VPN usage during high-value transactions
  • Tor exit nodes attempting account access
  • Residential proxies masking true origin
  • Datacenter IPs pretending to be residential users

Network Characteristics

  • Multiple accounts from the same IP address
  • IP ranges associated with hosting providers
  • ASNs known for abuse or bulletproof hosting
  • IPs appearing on threat intelligence feeds

The Risk Scoring Approach

Rather than blocking based on single signals, modern fraud prevention uses risk scores that aggregate multiple factors:

function calculateFraudRisk(ipData, transactionData, userHistory) {
let riskScore = 0;
const reasons = [];
// IP-based signals (0-40 points)
if (ipData.security.is_vpn) {
riskScore += 15;
reasons.push("vpn_detected");
}
if (ipData.security.is_tor) {
riskScore += 30;
reasons.push("tor_exit_node");
}
if (ipData.security.is_datacenter) {
riskScore += 10;
reasons.push("datacenter_ip");
}
if (ipData.security.threat_lists.length > 0) {
riskScore += 20;
reasons.push("threat_list_match");
}
// Geographic signals (0-30 points)
const countryMismatch =
transactionData.billingCountry !== ipData.location.country_code;
if (countryMismatch) {
riskScore += 25;
reasons.push("country_mismatch");
}
// Behavioral signals (0-30 points)
const isNewLocation = !userHistory.locations.includes(
ipData.location.country_code,
);
if (isNewLocation && userHistory.accountAge < 30) {
riskScore += 20;
reasons.push("new_location_new_account");
}
return {
score: Math.min(riskScore, 100),
reasons,
recommendation: getRecommendation(riskScore),
};
}
function getRecommendation(score) {
if (score >= 80) return "BLOCK";
if (score >= 60) return "MANUAL_REVIEW";
if (score >= 40) return "STEP_UP_AUTH";
if (score >= 20) return "MONITOR";
return "ALLOW";
}

Fraud Prevention Use Cases

Payment Fraud Prevention

E-commerce payment fraud is the most financially damaging fraud type. IP intelligence helps identify suspicious transactions before authorization.

Pre-Authorization Checks

async function checkPaymentFraud(ip, payment) {
const ipData = await fetch(`https://api.ipbot.com/${ip}`).then((r) =>
r.json(),
);
const checks = {
// Geographic verification
locationMatch: ipData.location.country_code === payment.billingCountry,
// Anonymization detection
isAnonymized:
ipData.security.is_vpn ||
ipData.security.is_proxy ||
ipData.security.is_tor,
// Risk assessment
riskScore: ipData.security.risk_score,
// Network type
isResidential: !ipData.security.is_datacenter,
};
// High-risk indicators
if (payment.amount > 500 && checks.isAnonymized) {
return {
action: "REQUIRE_3DS",
reason: "High-value transaction from anonymized connection",
};
}
if (!checks.locationMatch && checks.riskScore > 50) {
return {
action: "DECLINE",
reason: "Geographic mismatch with elevated risk",
};
}
if (checks.riskScore > 70) {
return {
action: "MANUAL_REVIEW",
reason: "High risk score",
};
}
return { action: "APPROVE" };
}

Velocity Checks

Track transaction patterns from individual IPs:

class VelocityTracker {
constructor(redisClient) {
this.redis = redisClient;
}
async checkVelocity(ip, userId) {
const now = Date.now();
const hourAgo = now - 3600000;
const dayAgo = now - 86400000;
// Track transactions per IP
const ipKey = `velocity:ip:${ip}`;
const userKey = `velocity:user:${userId}`;
const [ipTxns, userTxns] = await Promise.all([
this.redis.zrangebyscore(ipKey, hourAgo, now),
this.redis.zrangebyscore(userKey, dayAgo, now),
]);
const alerts = [];
// More than 5 transactions from same IP in 1 hour
if (ipTxns.length > 5) {
alerts.push({
type: "IP_VELOCITY",
message: `${ipTxns.length} transactions from IP in last hour`,
severity: "high",
});
}
// More than 20 transactions from user in 24 hours
if (userTxns.length > 20) {
alerts.push({
type: "USER_VELOCITY",
message: `${userTxns.length} transactions in last 24 hours`,
severity: "medium",
});
}
return alerts;
}
async recordTransaction(ip, userId, transactionId) {
const now = Date.now();
await Promise.all([
this.redis.zadd(`velocity:ip:${ip}`, now, transactionId),
this.redis.zadd(`velocity:user:${userId}`, now, transactionId),
// Expire keys after 24 hours
this.redis.expire(`velocity:ip:${ip}`, 86400),
this.redis.expire(`velocity:user:${userId}`, 86400),
]);
}
}

Account Takeover Prevention

Account takeover (ATO) is a growing threat where attackers gain access to legitimate user accounts. IP intelligence helps detect unauthorized access.

Login Anomaly Detection

async function detectLoginAnomaly(userId, ip) {
const [ipData, loginHistory] = await Promise.all([
fetch(`https://api.ipbot.com/${ip}`).then((r) => r.json()),
getLoginHistory(userId, 30), // Last 30 days
]);
const anomalies = [];
// Check if this is a new location
const knownCountries = new Set(loginHistory.map((l) => l.country_code));
if (!knownCountries.has(ipData.location.country_code)) {
anomalies.push({
type: "NEW_COUNTRY",
severity: "high",
details: {
newCountry: ipData.location.country_code,
knownCountries: Array.from(knownCountries),
},
});
}
// Check for impossible travel
const lastLogin = loginHistory[0];
if (lastLogin) {
const hoursSinceLastLogin = (Date.now() - lastLogin.timestamp) / 3600000;
const distanceKm = calculateDistance(
lastLogin.latitude,
lastLogin.longitude,
ipData.location.latitude,
ipData.location.longitude,
);
// Assume max travel speed of 900 km/h (commercial flight)
const possibleDistance = hoursSinceLastLogin * 900;
if (distanceKm > possibleDistance) {
anomalies.push({
type: "IMPOSSIBLE_TRAVEL",
severity: "critical",
details: {
distanceKm,
hoursSinceLastLogin,
possibleDistance,
},
});
}
}
// Check for anonymization during login
if (ipData.security.is_vpn || ipData.security.is_tor) {
// Only flag if user doesn't normally use VPN
const vpnLogins = loginHistory.filter((l) => l.is_vpn).length;
const vpnRatio = vpnLogins / loginHistory.length;
if (vpnRatio < 0.1) {
// Less than 10% VPN use historically
anomalies.push({
type: "UNUSUAL_VPN",
severity: "medium",
details: {
historicalVpnRatio: vpnRatio,
currentConnection: ipData.security.is_tor ? "tor" : "vpn",
},
});
}
}
return anomalies;
}
function calculateDistance(lat1, lon1, lat2, lon2) {
const R = 6371; // Earth's radius in km
const dLat = ((lat2 - lat1) * Math.PI) / 180;
const dLon = ((lon2 - lon1) * Math.PI) / 180;
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos((lat1 * Math.PI) / 180) *
Math.cos((lat2 * Math.PI) / 180) *
Math.sin(dLon / 2) *
Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}

Account Creation Fraud

Fraudsters create fake accounts for various purposes: promotional abuse, review manipulation, spam, and as staging for future attacks.

Registration Fraud Detection

import requests
from datetime import datetime, timedelta
class RegistrationFraudDetector:
def __init__(self, redis_client):
self.redis = redis_client
def analyze_registration(self, ip_address: str, email: str) -> dict:
# Get IP intelligence
ip_data = requests.get(f'https://api.ipbot.com/{ip_address}').json()
signals = []
risk_score = 0
# Check for datacenter/hosting IP
if ip_data['security']['is_datacenter']:
signals.append('datacenter_ip')
risk_score += 25
# Check for proxy/VPN
if ip_data['security']['is_proxy'] or ip_data['security']['is_vpn']:
signals.append('anonymized_connection')
risk_score += 20
# Check for Tor
if ip_data['security']['is_tor']:
signals.append('tor_exit_node')
risk_score += 35
# Check threat lists
if ip_data['security']['threat_lists']:
signals.append('threat_list_match')
risk_score += 30
# Check registration velocity from this IP
reg_count = self.get_recent_registrations(ip_address)
if reg_count > 3:
signals.append('high_registration_velocity')
risk_score += 20
# Check disposable email
if self.is_disposable_email(email):
signals.append('disposable_email')
risk_score += 25
# Determine action
if risk_score >= 70:
action = 'BLOCK'
elif risk_score >= 50:
action = 'REQUIRE_PHONE_VERIFICATION'
elif risk_score >= 30:
action = 'SHOW_CAPTCHA'
else:
action = 'ALLOW'
return {
'risk_score': min(risk_score, 100),
'signals': signals,
'action': action,
'ip_data': {
'country': ip_data['location']['country_code'],
'is_vpn': ip_data['security']['is_vpn'],
'risk_score': ip_data['security']['risk_score']
}
}
def get_recent_registrations(self, ip: str) -> int:
key = f'registrations:{ip}'
return self.redis.zcount(key, '-inf', '+inf')
def record_registration(self, ip: str, user_id: str):
key = f'registrations:{ip}'
self.redis.zadd(key, {user_id: datetime.now().timestamp()})
self.redis.expire(key, 86400) # 24 hour window
def is_disposable_email(self, email: str) -> bool:
domain = email.split('@')[1].lower()
disposable_domains = {'tempmail.com', 'throwaway.email', '10minutemail.com'}
return domain in disposable_domains

Building a Fraud Prevention Pipeline

A robust fraud prevention system combines multiple signals and uses a layered approach.

Architecture Overview

User Action --> IP Intelligence --> Risk Engine --> Decision
| |
v v
[Cache Layer] [ML Model]
|
v
[Rules Engine]
|
+-----------+-----------+
| | |
ALLOW CHALLENGE BLOCK

Implementation

class FraudPreventionPipeline {
constructor(config) {
this.cache = new IPCache({ ttl: 3600000 });
this.rules = config.rules || [];
this.mlModel = config.mlModel;
}
async evaluate(context) {
const { ip, userId, action, metadata } = context;
// Step 1: Get IP intelligence (with caching)
const ipData = await this.getIPData(ip);
// Step 2: Enrich context
const enrichedContext = {
...context,
ip: {
...ipData,
risk_score: ipData.security.risk_score,
is_anonymized:
ipData.security.is_vpn ||
ipData.security.is_proxy ||
ipData.security.is_tor,
threat_level: ipData.security.threat_level,
},
};
// Step 3: Apply rule-based checks
const ruleResults = this.evaluateRules(enrichedContext);
// Step 4: ML scoring (optional)
let mlScore = 0;
if (this.mlModel) {
mlScore = await this.mlModel.predict(enrichedContext);
}
// Step 5: Combine scores
const combinedScore = this.combineScores(ruleResults, mlScore);
// Step 6: Make decision
const decision = this.makeDecision(combinedScore, action);
// Step 7: Log for analysis
await this.logDecision(enrichedContext, decision);
return decision;
}
async getIPData(ip) {
// Check cache
let data = this.cache.get(ip);
if (data) return data;
// Fetch from API
const response = await fetch(`https://api.ipbot.com/${ip}`);
data = await response.json();
// Cache based on risk
const ttl = data.security.risk_score > 50 ? 1800000 : 3600000;
this.cache.set(ip, data, ttl);
return data;
}
evaluateRules(context) {
const results = [];
for (const rule of this.rules) {
if (this.matchesCondition(rule.condition, context)) {
results.push({
rule: rule.name,
score: rule.score,
action: rule.action,
});
}
}
return results;
}
matchesCondition(condition, context) {
// Simple condition matching
const { field, operator, value } = condition;
const contextValue = this.getNestedValue(context, field);
switch (operator) {
case "eq":
return contextValue === value;
case "gt":
return contextValue > value;
case "lt":
return contextValue < value;
case "in":
return value.includes(contextValue);
case "contains":
return contextValue?.includes(value);
default:
return false;
}
}
getNestedValue(obj, path) {
return path.split(".").reduce((o, p) => o?.[p], obj);
}
combineScores(ruleResults, mlScore) {
// Weight rule-based and ML scores
const ruleScore = ruleResults.reduce((sum, r) => sum + r.score, 0);
if (this.mlModel) {
// 60% rules, 40% ML
return ruleScore * 0.6 + mlScore * 0.4;
}
return ruleScore;
}
makeDecision(score, action) {
// Action-specific thresholds
const thresholds = {
login: { block: 80, challenge: 50, monitor: 30 },
payment: { block: 70, challenge: 40, monitor: 20 },
registration: { block: 60, challenge: 35, monitor: 15 },
};
const t = thresholds[action] || thresholds.login;
if (score >= t.block) return { action: "BLOCK", score };
if (score >= t.challenge) return { action: "CHALLENGE", score };
if (score >= t.monitor) return { action: "MONITOR", score };
return { action: "ALLOW", score };
}
async logDecision(context, decision) {
// Log for analysis and model training
console.log({
timestamp: new Date().toISOString(),
ip: context.ip,
userId: context.userId,
action: context.action,
decision: decision.action,
score: decision.score,
});
}
}
// Example usage
const pipeline = new FraudPreventionPipeline({
rules: [
{
name: "tor_block",
condition: { field: "ip.security.is_tor", operator: "eq", value: true },
score: 40,
action: "BLOCK",
},
{
name: "high_risk_ip",
condition: { field: "ip.risk_score", operator: "gt", value: 70 },
score: 30,
action: "CHALLENGE",
},
{
name: "datacenter_payment",
condition: {
field: "ip.security.is_datacenter",
operator: "eq",
value: true,
},
score: 20,
action: "MONITOR",
},
],
});
const decision = await pipeline.evaluate({
ip: "185.220.101.42",
userId: "user_123",
action: "payment",
metadata: { amount: 499.99 },
});

Reducing False Positives

High false positive rates erode customer trust and increase operational costs. Balance security with user experience.

Contextual Decisioning

Consider the full context, not just IP signals:

function adjustForContext(ipRisk, context) {
let adjustment = 0;
// Returning customer with purchase history
if (context.customerLifetimeValue > 1000) {
adjustment -= 15;
}
// Account age reduces risk
if (context.accountAgeDays > 365) {
adjustment -= 10;
}
// Previous successful transactions from this IP
if (context.previousSuccessfulTxns > 5) {
adjustment -= 20;
}
// Device fingerprint matches known device
if (context.isKnownDevice) {
adjustment -= 15;
}
return Math.max(0, ipRisk + adjustment);
}

VPN Handling

Not all VPN users are fraudsters. Handle them thoughtfully:

function handleVPNUser(ipData, context) {
// Allow VPNs for privacy-sensitive actions
const privacySensitiveActions = ["medical", "legal", "financial_planning"];
if (privacySensitiveActions.includes(context.category)) {
return "ALLOW_WITH_LOGGING";
}
// Known VPN user (historically uses VPN)
if (context.userHistoricalVpnRate > 0.5) {
return "ALLOW";
}
// Corporate VPN ranges
if (isKnownCorporateVPN(ipData.network.asn)) {
return "ALLOW";
}
// First-time VPN use on high-value transaction
if (context.transactionValue > 500 && context.userHistoricalVpnRate < 0.1) {
return "STEP_UP_AUTH";
}
return "MONITOR";
}

Metrics and Monitoring

Track key metrics to optimize your fraud prevention:

MetricDescriptionTarget
Detection Rate% of fraud caught> 95%
False Positive Rate% of legitimate users flagged< 2%
Review Rate% of transactions needing manual review< 5%
Block Rate% of transactions blocked< 1%
Customer FrictionAverage extra steps per transaction< 0.1

Monitoring Dashboard

class FraudMetrics {
constructor(redis) {
this.redis = redis;
}
async recordDecision(decision, wasActuallyFraud) {
const date = new Date().toISOString().split("T")[0];
const key = `fraud:metrics:${date}`;
await this.redis.hincrby(key, "total", 1);
await this.redis.hincrby(key, `decision:${decision}`, 1);
if (wasActuallyFraud) {
await this.redis.hincrby(key, "actual_fraud", 1);
if (decision === "BLOCK" || decision === "CHALLENGE") {
await this.redis.hincrby(key, "true_positive", 1);
} else {
await this.redis.hincrby(key, "false_negative", 1);
}
} else {
if (decision === "BLOCK" || decision === "CHALLENGE") {
await this.redis.hincrby(key, "false_positive", 1);
}
}
}
async getMetrics(date) {
const key = `fraud:metrics:${date}`;
const data = await this.redis.hgetall(key);
const total = parseInt(data.total) || 1;
const truePositive = parseInt(data.true_positive) || 0;
const falsePositive = parseInt(data.false_positive) || 0;
const falseNegative = parseInt(data.false_negative) || 0;
return {
total,
detectionRate: truePositive / (truePositive + falseNegative) || 0,
falsePositiveRate: falsePositive / total,
blockRate: (parseInt(data["decision:BLOCK"]) || 0) / total,
reviewRate: (parseInt(data["decision:CHALLENGE"]) || 0) / total,
};
}
}

Conclusion

IP intelligence is a foundational layer of modern fraud prevention. By combining geolocation, risk scoring, and proxy detection with behavioral signals and contextual data, you can build robust defenses that protect your business while maintaining a good user experience.

Key takeaways:

  1. Use risk scores, not binary decisions - Aggregate multiple signals for nuanced decisioning
  2. Cache intelligently - IP data is stable; cache for hours, not seconds
  3. Consider context - The same IP signal means different things in different scenarios
  4. Monitor and iterate - Track false positives and continuously tune thresholds
  5. Layer your defenses - IP intelligence is one component; combine with device fingerprinting, behavioral analysis, and ML

Ready to implement IP-based fraud prevention? Get started with IPBot - no API key required.