Technical Guide

IP Geolocation API: Complete Developer Guide

Everything you need to know about IP geolocation APIs: how they work, what data they return, and how to integrate them for content personalization, fraud prevention, and geo-restrictions. Includes code examples in cURL, JavaScript, Python, and C#.

Sofia Marquez
March 8, 2026 · 14 min read · Last reviewed

What is IP Geolocation?

IP geolocation is the process of determining the physical location of a device using its IP address. Every device connected to the internet has an IP address, and these addresses are allocated to ISPs and organizations in geographic blocks. By mapping these allocations, an IP geolocation API can determine a visitor's country, region, city, postal code, coordinates, and timezone, all from a single API call.

Unlike GPS or browser-based geolocation (which requires user permission), IP geolocation works server-side with no client interaction. This makes it ideal for use cases where you need location data before the page loads or without prompting the user.

IP Geolocation vs. GPS vs. Browser Geolocation:

IP geolocation works server-side, requires no user permission, and provides city-level accuracy. GPS provides meter-level precision but requires device hardware and user consent. Browser Geolocation API uses GPS/Wi-Fi/cell towers, requires user permission via a popup, and doesn't work server-side. For most web applications, IP geolocation is the right choice for initial location detection, with browser geolocation as an optional upgrade for precision-critical features.

How IP Geolocation Works

IP geolocation databases are built by mapping IP address ranges to geographic locations. Here's how the process works:

  1. IP allocation records: Regional Internet Registries (ARIN, RIPE, APNIC, etc.) publish which IP blocks are assigned to which organizations and in which countries.
  2. ISP and organization mapping: ISPs are assigned IP ranges for specific service areas. By mapping ISPs to their coverage areas, geolocation databases can narrow down locations to the region or city level.
  3. Active probing and crowdsourced data: Network measurements like latency-based triangulation and crowdsourced Wi-Fi/GPS correlations refine city-level accuracy.
  4. Continuous updates: IP allocations change as ISPs expand, merge, or reassign blocks. Geolocation databases are updated regularly to maintain accuracy.

When you call an IP geolocation API, it looks up the IP address in its pre-indexed database and returns the associated location data. This is why lookups are extremely fast (typically under 50ms) since there's no real-time network tracing involved.

What Data Does the API Return?

A typical IP geolocation API response includes a rich set of location and network data. Here's what sthan.io's IP Geolocation API returns:

{
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "Result": {
        "ipAddress": "8.8.8.8",
        "country": "United States",
        "countryCode": "US",
        "region": "California",
        "city": "Mountain View",
        "postalCode": "94043",
        "latitude": 37.422,
        "longitude": -122.085,
        "timezone": "America/Los_Angeles",
        "timezoneDetail": { "id": "America/Los_Angeles", "utcOffset": "-07:00", "offsetSeconds": -25200, "isDst": true, "currentLocalTime": "2026-10-01T13:13:59-07:00" },
        "continent": "North America",
        "continentCode": "NA",
        "regionCode": "CA",
        "type": "IPv4",
        "precision": "city",
        "countryNativeName": "United States",
        "isEu": false,
        "callingCode": "+1",
        "capital": "Washington, D.C.",
        "borders": ["CA", "MX"],
        "currency": { "code": "USD", "name": "United States dollar", "symbol": "$" },
        "languages": ["English"],
        "tld": ".us",
        "flag": { "emoji": "πŸ‡ΊπŸ‡Έ", "svg": "https://sthan.io/flags/us.svg" },
        "asn": 15169,
        "asName": "GOOGLE",
        "isp": "Google LLC",
        "organization": "Google Public DNS",
        "isMobile": false,
        "isProxy": true,
        "isHosting": true,
        "reverseDns": "dns.google",
        "confidence": 0.78
    },
    "statusCode": 200,
    "isError": false,
    "errors": []
}

Response Fields Explained

Field Description Example
ipAddress The IP address that was looked up 8.8.8.8
country Full country name United States
countryCode ISO 3166-1 alpha-2 country code US
region State, province, or administrative region California
city City name Mountain View
postalCode ZIP or postal code 94043
latitude Latitude coordinate 37.386
longitude Longitude coordinate -122.0838
timezone IANA timezone identifier America/Los_Angeles
continent Continent name North America
timezoneDetail UTC offset, daylight-saving flag and the current local time at the address, ready to display 2026-10-01T13:13:59-07:00
precision How far down the answer goes: city, region or country. With region or country the city is empty and coordinates and local time are for that area's centre city
flag, currency, callingCode, capital, languages, tld, borders, isEu Country facts derived from the country code, so you can localise a page without a second lookup USD $, +1, https://sthan.io/flags/us.svg
asn, asName, isp, organization The network that owns the address 15169, GOOGLE, Google LLC
isMobile, isProxy, isHosting Mobile carrier; known proxy or VPN exit; data centre, cloud or anycast address. A hosting or proxy address does not locate a person false, true, true
reverseDns Reverse DNS name of the address when one exists dns.google
confidence 0 to 1, how strongly independent checks agreed on the city. Absent when the address is new to us (ask again in a few seconds) or when they did not agree well enough 0.78

Getting Started

Before making your first API call, you need:

The free tier includes 50,000 IP lookups per month, which is more than enough for development, testing, and many production applications.

No credit card required: You can start making API calls within minutes of signing up. The free tier has the same data quality and response times as paid plans. The only difference is the monthly volume limit.

Authentication

sthan.io uses a 2-step JWT authentication flow. First, get a token, then use it for API calls.

Step 1: Get a JWT Token

Send a GET request to /Auth/Token with your credentials in the headers:

curl -X GET "https://api.sthan.io/Auth/Token" \
  -H "profileName: YOUR_PROFILE_NAME" \
  -H "profilePassword: YOUR_PROFILE_PASSWORD"

Response:

{
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "Result": {
        "access_token": "eyJhbGciOiJIUzI1NiIs...",
        "expiration": "2026-03-08T21:00:00Z"
    },
    "statusCode": 200,
    "isError": false,
    "errors": []
}

Step 2: Use the Token

Include the token as a Bearer token in the Authorization header for all subsequent API calls. Tokens expire after a set period, so your code should handle token refresh.

Token Management Tip:

Cache the token and reuse it until it expires. Check the expiration field before each request and refresh only when needed. This avoids unnecessary auth calls and keeps your integration fast.

Your First IP Lookup

With your token in hand, you can look up any IP address. The endpoint is:

GET /IpGeolocation/{ip}

Replace {ip} with an IPv4 or IPv6 address. Here are complete examples in 11 languages; each gets a token, looks up 8.8.8.8 and prints the response (for 8.8.8.8: Mountain View, California, United States).

# Step 1: Get your auth token (uses jq to read Result.access_token)
TOKEN=$(curl -s "https://api.sthan.io/Auth/Token" \
  -H "profileName: YOUR_PROFILE_NAME" \
  -H "profilePassword: YOUR_PROFILE_PASSWORD" | jq -r '.Result.access_token')

# Step 2: Make the API call
curl -s "https://api.sthan.io/IpGeolocation/8.8.8.8" \
  -H "Authorization: Bearer $TOKEN"
// Node.js 18+ (save as example.mjs, run: node example.mjs)
// Step 1: Get your auth token
const auth = await fetch("https://api.sthan.io/Auth/Token", {
  headers: { profileName: "YOUR_PROFILE_NAME", profilePassword: "YOUR_PROFILE_PASSWORD" }
});
if (!auth.ok) throw new Error(`Auth failed: ${auth.status}`);
const { access_token } = (await auth.json()).Result;

// Step 2: Make the API call
const response = await fetch("https://api.sthan.io/IpGeolocation/8.8.8.8", {
  headers: { Authorization: `Bearer ${access_token}` }
});
console.log(await response.json());
import requests

# Step 1: Get your auth token
auth = requests.get(
    "https://api.sthan.io/Auth/Token",
    headers={"profileName": "YOUR_PROFILE_NAME", "profilePassword": "YOUR_PROFILE_PASSWORD"},
    timeout=10,
)
auth.raise_for_status()
token = auth.json()["Result"]["access_token"]

# Step 2: Make the API call
response = requests.get("https://api.sthan.io/IpGeolocation/8.8.8.8", headers={"Authorization": f"Bearer {token}"}, timeout=10)
response.raise_for_status()
print(response.json())
// .NET 6+ console app (Program.cs)
using System.Net.Http.Headers;
using System.Text.Json;

using var client = new HttpClient();

// Step 1: Get your auth token
var authRequest = new HttpRequestMessage(HttpMethod.Get, "https://api.sthan.io/Auth/Token");
authRequest.Headers.Add("profileName", "YOUR_PROFILE_NAME");
authRequest.Headers.Add("profilePassword", "YOUR_PROFILE_PASSWORD");
using var authResponse = await client.SendAsync(authRequest);
authResponse.EnsureSuccessStatusCode();
using var authJson = JsonDocument.Parse(await authResponse.Content.ReadAsStringAsync());
var token = authJson.RootElement.GetProperty("Result").GetProperty("access_token").GetString();

// Step 2: Make the API call
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetStringAsync("https://api.sthan.io/IpGeolocation/8.8.8.8");
Console.WriteLine(response);
// Java 11+, no extra libraries. Save as Example.java, run: java Example.java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Example {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        // Step 1: Get your auth token
        HttpRequest authRequest = HttpRequest.newBuilder(URI.create("https://api.sthan.io/Auth/Token"))
            .header("profileName", "YOUR_PROFILE_NAME")
            .header("profilePassword", "YOUR_PROFILE_PASSWORD")
            .build();
        String authBody = client.send(authRequest, HttpResponse.BodyHandlers.ofString()).body();
        // The token is at Result.access_token (read it with your JSON library, or like this)
        Matcher m = Pattern.compile("\"access_token\"\\s*:\\s*\"([^\"]+)\"").matcher(authBody);
        if (!m.find()) throw new IllegalStateException("No token in: " + authBody);
        String token = m.group(1);

        // Step 2: Make the API call
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.sthan.io/IpGeolocation/8.8.8.8"))
            .header("Authorization", "Bearer " + token)
            .build();
        System.out.println(client.send(request, HttpResponse.BodyHandlers.ofString()).body());
    }
}
<?php
// PHP 7.4+ with the curl extension

// Step 1: Get your auth token
$ch = curl_init("https://api.sthan.io/Auth/Token");
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ["profileName: YOUR_PROFILE_NAME", "profilePassword: YOUR_PROFILE_PASSWORD"],
    CURLOPT_RETURNTRANSFER => true,
]);
$auth = json_decode(curl_exec($ch), true);
$token = $auth["Result"]["access_token"];

// Step 2: Make the API call
$ch = curl_init("https://api.sthan.io/IpGeolocation/8.8.8.8");
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $token],
    CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch), PHP_EOL;
require "net/http"
require "json"

# Step 1: Get your auth token
uri = URI("https://api.sthan.io/Auth/Token")
req = Net::HTTP::Get.new(uri)
req["profileName"] = "YOUR_PROFILE_NAME"
req["profilePassword"] = "YOUR_PROFILE_PASSWORD"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
token = JSON.parse(res.body)["Result"]["access_token"]

# Step 2: Make the API call
uri = URI("https://api.sthan.io/IpGeolocation/8.8.8.8")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	// Step 1: Get your auth token
	authReq, _ := http.NewRequest("GET", "https://api.sthan.io/Auth/Token", nil)
	authReq.Header.Set("profileName", "YOUR_PROFILE_NAME")
	authReq.Header.Set("profilePassword", "YOUR_PROFILE_PASSWORD")
	authResp, err := http.DefaultClient.Do(authReq)
	if err != nil {
		panic(err)
	}
	defer authResp.Body.Close()
	var auth struct {
		Result struct {
			AccessToken string `json:"access_token"`
		}
	}
	if err := json.NewDecoder(authResp.Body).Decode(&auth); err != nil {
		panic(err)
	}

	// Step 2: Make the API call
	req, _ := http.NewRequest("GET", "https://api.sthan.io/IpGeolocation/8.8.8.8", nil)
	req.Header.Set("Authorization", "Bearer "+auth.Result.AccessToken)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }
//             tokio = { version = "1", features = ["full"] }, serde_json = "1"
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Step 1: Get your auth token
    let auth: serde_json::Value = client
        .get("https://api.sthan.io/Auth/Token")
        .header("profileName", "YOUR_PROFILE_NAME")
        .header("profilePassword", "YOUR_PROFILE_PASSWORD")
        .send()
        .await?
        .error_for_status()?
        .json()
        .await?;
    let token = auth["Result"]["access_token"].as_str().ok_or("no token in response")?;

    // Step 2: Make the API call
    let body = client
        .get("https://api.sthan.io/IpGeolocation/8.8.8.8")
        .bearer_auth(token)
        .send()
        .await?
        .text()
        .await?;
    println!("{body}");
    Ok(())
}
// Kotlin (JVM 11+), no extra libraries
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse

fun main() {
    val client = HttpClient.newHttpClient()

    // Step 1: Get your auth token
    val authRequest = HttpRequest.newBuilder(URI.create("https://api.sthan.io/Auth/Token"))
        .header("profileName", "YOUR_PROFILE_NAME")
        .header("profilePassword", "YOUR_PROFILE_PASSWORD")
        .build()
    val authBody = client.send(authRequest, HttpResponse.BodyHandlers.ofString()).body()
    // The token is at Result.access_token (read it with your JSON library, or like this)
    val token = Regex("\"access_token\"\\s*:\\s*\"([^\"]+)\"").find(authBody)?.groupValues?.get(1)
        ?: error("No token in: $authBody")

    // Step 2: Make the API call
    val request = HttpRequest.newBuilder(URI.create("https://api.sthan.io/IpGeolocation/8.8.8.8"))
        .header("Authorization", "Bearer $token")
        .build()
    println(client.send(request, HttpResponse.BodyHandlers.ofString()).body())
}
# Run as a script: elixir example.exs
# (in a Mix project, add {:req, "~> 0.5"} to deps and drop the next line)
Mix.install([{:req, "~> 0.5"}])

# Step 1: Get your auth token
auth =
  Req.get!("https://api.sthan.io/Auth/Token",
    headers: [{"profileName", "YOUR_PROFILE_NAME"}, {"profilePassword", "YOUR_PROFILE_PASSWORD"}]
  )

token = auth.body["Result"]["access_token"]

# Step 2: Make the API call
response = Req.get!("https://api.sthan.io/IpGeolocation/8.8.8.8", auth: {:bearer, token})
IO.inspect(response.body)
Try it live: Visit the IP Geolocation demo page to test the API in your browser with no setup required.

Real-World Use Cases

IP geolocation powers a wide range of features across industries. Here are the most impactful use cases with implementation guidance.

1. Content Personalization

Automatically adapt your application based on where visitors are located. This creates a more relevant experience without requiring users to manually set their preferences.

  • Currency & pricing: Show prices in the visitor's local currency. An e-commerce site can display USD for US visitors and EUR for European visitors.
  • Language: Pre-select the user's language based on their country code. Use the countryCode field to map to your supported languages.
  • Region-specific content: Show local promotions, store locations, or shipping estimates based on the visitor's region.
  • Timezone-aware scheduling: Use the timezone field to display dates, times, and deadlines in the visitor's local timezone.
// Example: Auto-select currency based on visitor location
// (token from Step 1; the response already carries the country's currency)
async function getVisitorCurrency(token, visitorIp) {
    const res = await fetch(`https://api.sthan.io/IpGeolocation/${visitorIp}`, {
        headers: { Authorization: `Bearer ${token}` }
    });
    if (!res.ok) return "USD";
    const location = (await res.json()).Result;
    return location.currency?.code ?? "USD";
}

2. Fraud Prevention

IP geolocation is one of the most effective signals for detecting fraudulent activity. Use it to add a location-based risk layer to your security.

  • Login anomaly detection: Compare the login IP's location with the user's known locations. Flag logins from unexpected countries or regions.
  • Billing address mismatch: Compare the IP's country with the billing address country at checkout. A mismatch is a common fraud signal.
  • Impossible travel: If a user logs in from New York and then from Tokyo 30 minutes later, flag the second session for review.
# Example: Detect suspicious login location
import requests

def lookup_ip(token, ip):
    """Return the Result object for one IP address."""
    response = requests.get(
        f"https://api.sthan.io/IpGeolocation/{ip}",
        headers={"Authorization": f"Bearer {token}"},
        timeout=10,
    )
    response.raise_for_status()
    return response.json()["Result"]

def check_login_risk(token, login_ip, user_country):
    """Compare login IP location with the user's registered country."""
    location = lookup_ip(token, login_ip)

    if location["countryCode"] != user_country:
        return {
            "risk": "high",
            "reason": f"Login from {location['country']} "
                       f"(expected: {user_country})",
            "ip": login_ip,
            "city": location["city"],
        }

    return {"risk": "low"}

3. Geo-Restrictions & Compliance

Some content and services need to be restricted by geography due to licensing agreements, regulations, or sanctions compliance.

  • Content licensing: Streaming services restrict content libraries by region. Use the countryCode to enforce access rules.
  • Regulatory compliance: Financial services, gambling platforms, and healthcare applications may need to restrict access based on jurisdiction.
  • Export controls: Block access from sanctioned countries or regions as required by your legal obligations.
// Example: Geo-restriction middleware in ASP.NET Core
// Register it with: app.UseMiddleware<GeoRestrictionMiddleware>();
// IIpGeolocationService is your own wrapper around the lookup above; it returns Result.countryCode.
public interface IIpGeolocationService
{
    Task<string?> GetCountryCodeAsync(string ip);
}

public class GeoRestrictionMiddleware
{
    private static readonly HashSet<string> BlockedCountries = new()
    {
        "KP", "IR", "SY"  // Example sanctioned country codes
    };

    private readonly RequestDelegate _next;

    public GeoRestrictionMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context, IIpGeolocationService geoService)
    {
        var ip = context.Connection.RemoteIpAddress?.ToString();
        if (ip != null)
        {
            var countryCode = await geoService.GetCountryCodeAsync(ip);
            if (countryCode != null && BlockedCountries.Contains(countryCode))
            {
                context.Response.StatusCode = 403;
                await context.Response.WriteAsync("Service not available in your region.");
                return;
            }
        }

        await _next(context);
    }
}

4. Analytics & Reporting

Enrich your analytics with geographic context to understand where your users are and how usage varies by region.

  • Traffic origin dashboards: Visualize where your traffic comes from on a map using latitude/longitude coordinates.
  • Regional conversion rates: Break down sign-ups, purchases, and engagement by country or region to identify growth opportunities.
  • Timezone distribution: Understand when your users are most active by mapping their timezones, helping you schedule releases, maintenance, and campaigns.

Understanding Accuracy Levels

IP geolocation accuracy isn't uniform. It varies by the level of detail you need and the type of IP address.

Level Typical Accuracy Notes
Country 99%+ Highly reliable for nearly all IP types
Region / State 90–95% Very reliable for fixed broadband
City 70–90% Varies by ISP and region; best in urban areas
Postal Code 60–80% Useful as an approximation, not for precise targeting

Factors That Affect Accuracy

  • IP type: Fixed broadband IPs (home/office) are the most accurate. Mobile IPs shift as users move. VPN and proxy IPs reflect the server location, not the user.
  • ISP centralization: Some ISPs route traffic through a single point-of-presence, making all their users appear to be in one city.
  • CGNAT (Carrier-Grade NAT): Many mobile carriers and some ISPs share a single public IP among thousands of users, reducing location precision.
  • Regional coverage: Accuracy tends to be highest in North America and Western Europe, and lower in regions with less IP allocation data.
Practical advice: Design your features to gracefully handle inaccuracy. Use country-level data for critical decisions (compliance, currency) and city-level data for best-effort personalization. Never use IP geolocation as the sole factor for security decisions. Combine it with other signals.

Best Practices

1. Cache Results

IP geolocation data doesn't change frequently. Cache results for at least 24 hours to reduce API calls and latency. Use the IP address as the cache key.

# Example: Simple in-memory cache with TTL (uses lookup_ip from the fraud example above)
from datetime import datetime, timedelta, timezone

_cache = {}
CACHE_TTL = timedelta(hours=24)

def lookup_ip_cached(token, ip):
    """Look up IP with 24-hour cache."""
    now = datetime.now(timezone.utc)

    if ip in _cache:
        result, cached_at = _cache[ip]
        if now - cached_at < CACHE_TTL:
            return result

    result = lookup_ip(token, ip)
    _cache[ip] = (result, now)
    return result

2. Handle Errors Gracefully

Don't let a geolocation API failure break your application. Always have a fallback.

  • If the API is unavailable, default to a sensible fallback (e.g., US/English).
  • If an IP can't be located (private IPs, localhost), handle it as "unknown" rather than erroring out.
  • Set reasonable timeouts (5–10 seconds) so a slow response doesn't block your page load.

3. Respect User Preferences

IP geolocation provides a smart default, but always let users override it. Common patterns:

  • Auto-detect country/language, but show a dropdown to change it.
  • Store the user's explicit preference in a cookie or profile. Once they choose, stop relying on IP.
  • For logged-in users, prefer their profile settings over IP geolocation.

4. Don't Over-Rely on IP for Security

IP geolocation is a useful signal, not a definitive answer. For security-critical decisions:

  • Combine IP location with device fingerprinting, user behavior, and authentication factors.
  • Be aware that VPNs, proxies, and Tor can mask true locations.
  • Use IP geolocation to flag suspicious activity for review, not to automatically block users.

5. Consider Privacy

IP geolocation processes personal data (IP addresses). Follow these privacy guidelines:

  • Document your legal basis for processing (legitimate interest for fraud prevention, consent for analytics).
  • Mention IP geolocation in your privacy policy.
  • Don't store raw IP addresses longer than necessary. Store the derived location data instead where possible.
  • For EU visitors (GDPR), ensure your data processing agreements cover the IP geolocation provider.

Key Takeaways

  • IP geolocation works server-side with no user permission required, ideal for instant location detection at page load
  • Country-level accuracy is 99%+, making it reliable for currency, language, and compliance decisions
  • Cache results for 24 hours to reduce API calls. IP geolocation data changes infrequently
  • Combine with other signals for security. Never rely on IP geolocation alone for fraud prevention
  • Always provide user overrides. Use IP geolocation as a smart default, not a locked-in choice
  • sthan.io offers 50,000 free lookups/month with sub-50ms response times

Share This Article

Frequently Asked Questions

An IP Geolocation API determines the geographic location of a device based on its IP address. It returns data such as country, region, city, postal code, latitude, longitude, timezone, and ISP information. Developers use it for content personalization, fraud detection, geo-restrictions, analytics, and compliance.
Country-level detection is 99%+ accurate. Region/state-level is around 90–95%. City-level accuracy ranges from 70–90% depending on the ISP and region. Mobile IPs and VPN/proxy traffic tend to be less accurate than fixed broadband connections. For best results, use country-level data for critical decisions and city-level data for best-effort personalization.
Yes. sthan.io's IP Geolocation API handles both IPv4 and IPv6 addresses transparently. Pass either format to the endpoint and receive the same location data structure in response.
When a user connects through a VPN or proxy, the geolocation data reflects the VPN server's location, not the user's actual location. For fraud prevention, combining IP geolocation with other signals (browser timezone, language settings, device fingerprint) provides more reliable detection of masked locations.
sthan.io's IP Geolocation API delivers sub-50ms response times. Lookups are extremely fast because they query pre-indexed databases rather than performing real-time network traces. This makes it suitable for real-time use cases like page load personalization and login security checks.
IP addresses are considered personal data under GDPR, so you need a lawful basis for processing. Fraud prevention and security qualify as legitimate interests. For analytics and personalization, ensure you have consent where required. Document your legal basis, include IP geolocation in your privacy policy, and avoid storing raw IPs longer than necessary.
The most common use cases include: content personalization (language, currency, regional content), fraud prevention (suspicious login detection, billing address mismatch), geo-restrictions (content licensing, regulatory compliance), analytics (traffic origin, regional conversion rates), and ad targeting (serving location-relevant advertisements).

Start Using IP Geolocation

Get 50,000 free IP lookups per month. Detect visitor locations, prevent fraud, and personalize content. No credit card required.

Sofia Marquez
Written by Sofia Marquez

Sofia Marquez writes about geocoding, reverse geocoding and IP geolocation for developers.

More from Sofia Marquez