How to Detect Suspicious Logins Using IP Geolocation?

In an era where credential stuffing and account takeover (ATO) attacks are automated at scale, relying solely on a username and password is a significant security risk. For backend engineers, adding a layer of IP intelligence is one of the most effective ways to identify unauthorized access without introducing excessive friction for legitimate users.

This post explores the technical implementation of IP-based login monitoring, focusing on how to use geolocation and network metadata to flag suspicious behavior.

Detecting suspicious login attempts using IP intelligence

What Is a Suspicious Login?

A login is considered suspicious when it deviates from a user’s established behavior patterns. Common examples include:

IP geolocation does not replace authentication or MFA, but it acts as an early warning signal that helps trigger additional verification or security actions.


How IP Geolocation Helps Detect Suspicious Logins

IP geolocation maps an IP address to geographic and network metadata, such as:

By comparing the login IP’s metadata with historical login data for the same user, backend systems can detect anomalies in near real time.

The Role of IP Intelligence in Security

IP geolocation is more than just mapping an IP address to a city. In a security context, it provides contextual metadata about the connection. When a user attempts to log in, the IP address carries signals that can be cross-referenced with historical data or security policies.

By analyzing the source IP, developers can detect:


Technical Implementation: The Logic Flow

To implement this, your authentication service should capture the client's IP address and query an IP intelligence API before or immediately after processing the credentials.

1. Capturing the IP

In a typical Node.js or Python backend, you extract the IP from the request headers. If you are behind a load balancer (like Nginx or AWS ALB), look for the X-Forwarded-For header.

2. Querying the IP2GeoAPI

A standard GET request to a geolocation service returns a JSON object containing the location and network data. Example Request (cURL):

curl -X GET "https://api.ip2geoapi.com/ip/8.8.8.8?key=YOUR_API_KEY"

You can get a free API key from us, which includes 100,000 free requests per month. Example JSON Response:

{
  "success": true,
  "ip": "8.8.8.8",
  "version": "ipv4",
  "geo": {
    "city": "Chicago",
    "country": "United States",
    "countryCode": "US",
    "region": null,
    "regionCode": null,
    "latitude": 37.751,
    "longitude": -97.822,
    "postalCode": null,
    "geonameId": 6252001,
    "accuracyRadius": 1000,
    "metroCode": null,
    "continentName": "North America",
    "continentCode": "NA",
    "isEuMember": false
  },
  "countryInfo": {
    "name": "United States of America",
    "alpha2Code": "US",
    "alpha3Code": "USA",
    "flag": "https://api.ip2geoapi.com/assets/flags/us.svg",
    "callingCodes": [
      "1"
    ],
    "currencies": [
      {
        "code": "USD",
        "name": "United States dollar",
        "symbol": "$"
      }
    ],
    "languages": [
      {
        "iso639_1": "en",
        "iso639_2": "eng",
        "name": "English",
        "nativeName": "English"
      }
    ]
  },
  "timezoneInfo": {
    "timezone": "America/Chicago",
    "utcOffsetSeconds": -21600,
    "utcOffsetText": "-06:00",
    "utcOffsetHours": -6,
    "isDst": false,
    "abbreviation": "CST",
    "localTime": "2026-01-14T21:48:33-06:00"
  },
  "network": {
    "cidr": "8.8.8.8/32",
    "prefixLen": 32,
    "asn": 15169,
    "asFormatted": "AS15169",
    "asName": "GOOGLE",
    "isp": "Google",
    "organization": "Google",
    "connectionType": "Corporate",
    "mobile": {
      "mcc": null,
      "mnc": null
    }
  },
  "asDetails": {
    "asn": 15169,
    "abuser_score": "0.001 (Low)",
    "descr": "GOOGLE, US",
    "country": "us",
    "active": true,
    "org": "Google LLC",
    "domain": "google.com",
    "abuse": "[email protected]",
    "type": "hosting",
    "created": "2000-03-30",
    "updated": "2012-02-24",
    "rir": "ARIN"
  },
  "security": {
    "isHosting": true,
    "isProxy": false,
    "proxyType": null,
    "isVpn": false,
    "vpnProvider": null,
    "vpnProviderUrl": null,
    "isTor": false,
    "isAnonymous": true,
    "trustScore": 65,
    "riskLevel": "medium"
  }
}

3. Verification Logic

Once the data is retrieved, the backend evaluates it against several rules:


Blocking Suspicious Logins: Python Implementation

Below is a clean, production-style Python example showing how to implement suspicious login detection using IP geolocation, based exactly on your real JSON structure from ip2geoapi. High-Level Logic

We will:

Example Stored Login Metadata (DB / Cache):

LAST_LOGIN = {
    "country_code": "IN",
    "asn": 55836,
    "timezone": "Asia/Kolkata",
    "timestamp": 1736856000  # unix epoch
}

Core Implementation

import requests
import time
from math import radians, cos, sin, asin, sqrt

API_KEY = "YOUR_API_KEY"
API_URL = "https://api.ip2geoapi.com/ip/{}?key={}"
TIME_TRAVEL_LIMIT_KM = 5000
TIME_WINDOW_SECONDS = 3600  # 1 hour

def fetch_ip_intel(ip: str) -> dict:
    resp = requests.get(API_URL.format(ip, API_KEY), timeout=20)
    resp.raise_for_status()
    data = resp.json()

    if not data.get("success"):
        raise ValueError("IP intelligence lookup failed")

    return data

def haversine(lat1, lon1, lat2, lon2):
    r = 6371  # Earth radius in km
    dlat = radians(lat2 - lat1)
    dlon = radians(lon2 - lon1)
    a = sin(dlat/2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a))
    return r * c

def evaluate_login_risk(ip_data: dict, last_login: dict | None):
    risk_score = 0
    reasons = []

    geo = ip_data["geo"]
    network = ip_data["network"]
    security = ip_data["security"]
    tz = ip_data["timezoneInfo"]

    # Hosting / VPN / Proxy signals
    if security["isHosting"]:
        risk_score += 40
        reasons.append("hosting_ip")

    if security["isVpn"] or security["isProxy"] or security["isTor"]:
        risk_score += 50
        reasons.append("anonymized_network")

    # Anonymous flag
    if security["isAnonymous"]:
        risk_score += 20
        reasons.append("anonymous_network")

    # Country change
    if last_login:
        if geo["countryCode"] != last_login["country_code"]:
            risk_score += 25
            reasons.append("country_change")

        # ASN change
        if network["asn"] != last_login["asn"]:
            risk_score += 15
            reasons.append("asn_change")

        # Impossible travel
        if geo["latitude"] and geo["longitude"]:
            distance = haversine(
                geo["latitude"],
                geo["longitude"],
                last_login.get("latitude", geo["latitude"]),
                last_login.get("longitude", geo["longitude"]),
            )

            delta = time.time() - last_login["timestamp"]
            if delta < TIME_WINDOW_SECONDS and distance > TIME_TRAVEL_LIMIT_KM:
                risk_score += 40
                reasons.append("impossible_travel")

    # Trust score from API
    if security["trustScore"] < 50:
        risk_score += 20
        reasons.append("low_trust_score")

    return risk_score, reasons

def decision_from_score(score: int):
    if score >= 70:
        return "block"
    elif score >= 40:
        return "challenge"  # MFA / OTP / Email verification
    return "allow"

def process_login(ip: str, last_login: dict | None):
    ip_data = fetch_ip_intel(ip)
    score, reasons = evaluate_login_risk(ip_data, last_login)

    decision = decision_from_score(score)

    return {
        "decision": decision,
        "risk_score": score,
        "reasons": reasons,
        "country": ip_data["geo"]["countryCode"],
        "asn": ip_data["network"]["asn"],
        "risk_level": ip_data["security"]["riskLevel"]
    }

Example Output:

{
  "decision": "challenge",
  "risk_score": 65,
  "reasons": [
    "hosting_ip",
    "country_change",
    "anonymous_network"
  ],
  "country": "US",
  "asn": 15169,
  "risk_level": "medium"
}

How to Use This in Production?

Real-World Use Cases

Account Takeover Prevention

If a user typically logs in from India and suddenly attempts to log in from Eastern Europe, the system can flag the attempt as high risk and require MFA.

SaaS Admin Account Protection

Admin or owner accounts can be restricted to specific countries or ASNs. Any login outside those parameters can be blocked outright.

Consumer Apps and E-commerce

For consumer applications, suspicious logins may not be blocked but can trigger alerts or email notifications.

Compliance and Audit Logging

Geolocation data is often stored alongside login logs to support forensic analysis and compliance requirements.

Accuracy Limitations and Edge Cases

IP geolocation is probabilistic, not exact. Developers should account for the following limitations:

Because of these factors, geolocation should never be the sole factor for blocking access.

Common Mistakes to Avoid

A balanced approach reduces false positives while still improving security.

Security Considerations

Conclusion

IP geolocation is a practical, low-friction way to detect suspicious login behavior when applied correctly. It provides geographic and network context that helps backend systems identify anomalies without disrupting legitimate users.

When combined with historical login data and sensible risk rules, IP geolocation significantly strengthens account security. APIs like ip2geoapi.com make this easy to implement at scale, with accurate data, IPv4/IPv6 support, and a generous free tier suitable for production testing. Used thoughtfully, IP geolocation becomes a reliable signal—not a blunt instrument—in modern authentication systems.

Ready to secure your app? Sign up for IP2GeoAPI and get your first 100K requests free.

Vijay Prajapati
About the Author

Vijay Prajapati

I am a backend developer and founder of IP2GeoAPI, specializing in IP geolocation, network intelligence, and API architecture. I focus on building fast, accurate and scalable APIs for developers.

Connect on LinkedIn

Ready to Integrate?

Start using our IP geolocation & intelligence API in minutes. Sign up now and get your FREE API key with 100,000 monthly quota every month — no credit card required.

Join developers worldwide who rely on IP2GeoAPI for speed, accuracy, and reliability.