IP GeolocationSecurityTutorial
IP Geolocation for Fraud Detection — A Developer's Guide
ApogeoAPI6 min read
IP geolocation is one of the most accessible fraud signals available. It won't stop sophisticated attackers, but it catches a significant amount of low-effort fraud with very little implementation overhead.
How IP Geolocation Helps Detect Fraud
- Impossible travel: A user logs in from Germany, then from Brazil 10 minutes later.
- Country mismatch: Billing address is in the US, but the IP is in a different region.
- High-risk region matching: Signups from regions associated with specific fraud patterns.
- VPN/proxy detection: Hiding location is sometimes a fraud signal (requires specialized APIs).
Signal 1: Impossible Travel
function haversineDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
const R = 6371; // Earth radius in km
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLon = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(dLat/2) ** 2 +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2) ** 2;
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
}
async function checkImpossibleTravel(userId: string, currentIp: string) {
const current = await geolocate(currentIp);
const lastLogin = await db.getLastLogin(userId);
if (!lastLogin) return false;
const distanceKm = haversineDistance(
lastLogin.latitude, lastLogin.longitude,
current.latitude, current.longitude
);
const hoursSince = (Date.now() - lastLogin.timestamp) / 3600000;
const maxPossibleSpeed = 900; // km/h (commercial flight speed)
return distanceKm / hoursSince > maxPossibleSpeed;
}
Signal 2: Country Mismatch
async function checkCountryMismatch(billingCountry: string, ip: string): Promise<boolean> {
const geo = await geolocate(ip);
return geo.country_code !== billingCountry;
}
Signal 3: High-Risk Regions
const HIGH_RISK_COUNTRIES = new Set(['XX', 'YY']); // Your own list based on data
async function isHighRiskRegion(ip: string): Promise<boolean> {
const geo = await geolocate(ip);
return HIGH_RISK_COUNTRIES.has(geo.country_code);
}
Signal 4: Anonymous IP / VPN
Standard IP geolocation APIs (including ApogeoAPI) don't detect VPNs or proxies — that requires a dedicated proxy detection database. Services like IPQualityScore or Fraudlabs Pro specialize in this. Use them as an additional layer, not a replacement.
Putting It Together: Risk Score
interface RiskResult {
score: number; // 0–100
reasons: string[];
}
async function calculateRiskScore(
userId: string,
ip: string,
billingCountry: string
): Promise<RiskResult> {
const reasons: string[] = [];
let score = 0;
const [impossible, mismatch, highRisk] = await Promise.all([
checkImpossibleTravel(userId, ip),
checkCountryMismatch(billingCountry, ip),
isHighRiskRegion(ip),
]);
if (impossible) { score += 40; reasons.push('Impossible travel detected'); }
if (mismatch) { score += 30; reasons.push('IP country does not match billing country'); }
if (highRisk) { score += 20; reasons.push('IP originates from high-risk region'); }
return { score, reasons };
}
Important Caveats
- Never block solely on IP. VPNs, corporate proxies, and shared IPs create false positives that block legitimate users.
- Use as one signal among many. Combine with device fingerprinting, behavioral analysis, and payment signals.
- Consider privacy regulations. Storing IP-derived location data may fall under GDPR or CCPA. Consult your legal team.
- Communicate clearly. If you flag a user, give them a way to verify identity rather than a silent block.
Try ApogeoAPI free
1,000 requests/month forever. 14-day full-access trial. No credit card.
Get your free API key