IPconf
Back to tutorials
API 10 min read

Build IP geolocation into your app

Calling the ipconf API from JavaScript, Node.js, Python, and Go — with practical caching, VPN handling, and privacy rules.

What IP geolocation can — and cannot — tell you

IP geolocation maps an IP to a likely country, region, and city based on databases of address allocations. It is typically accurate at the country level (>95%), reasonable at the region level (75-90%), and increasingly unreliable at the city level (50-80% depending on country).

It cannot tell you a street address, name, or identity. It can be wrong for VPN/proxy users, corporate networks with centralized egress, mobile users on carrier-grade NAT, and any cloud/VPS IP. Build your product to be useful when the location is right, and graceful when it is wrong.

Pick the right endpoint

`/api/ip` returns location for the caller — useful for "show local content" features. `/api/ip/{ip}` returns location for an arbitrary IP — useful for log analysis, fraud detection, or showing "this login came from X".

Add `?lang=zh` for Chinese place names. Default is English. Both endpoints return the same JSON schema.

// In the browser, for the current visitor:
fetch("https://api.ipconf.me/api/ip")
  .then(r => r.json())
  .then(data => console.log(data.country, data.city));

// For a specific IP:
fetch("https://api.ipconf.me/api/ip/8.8.8.8?lang=zh")
  .then(r => r.json())
  .then(data => console.log(data));

Server-side vs client-side calls

Calling from the browser uses the browser's IP — which is what you usually want for the current visitor. But it leaks the API URL to every visitor and is subject to ad blockers and CORS.

Calling from your server uses your server's outbound IP unless you explicitly pass the visitor's IP. Pass it as a path parameter to look up the right one. Server-side calls let you cache, retry, and centralize error handling.

// Node.js — get visitor IP from request, then look it up:
app.get("/local-content", async (req, res) => {
  const visitorIp = req.headers["cf-connecting-ip"]
    || req.headers["x-forwarded-for"]?.split(",")[0]
    || req.ip;
  const r = await fetch(`https://api.ipconf.me/api/ip/${visitorIp}`);
  const geo = await r.json();
  res.json({ visitor: visitorIp, country: geo.country });
});

Caching strategy

IP-to-location is stable on minutes-to-hours timescales for residential users, and for hours-to-days for static infrastructure IPs. You almost never need to look up the same IP twice within a minute.

In-process LRU cache (10-60 minutes TTL) is the simplest start. Add Redis if you have multiple servers. Avoid caching forever — IP allocations do change, and stale data leads to wrong content for real users.

// Node.js with a simple LRU + TTL:
import { LRUCache } from "lru-cache";
const cache = new LRUCache({ max: 10000, ttl: 30 * 60 * 1000 });

async function geo(ip) {
  if (cache.has(ip)) return cache.get(ip);
  const r = await fetch(`https://api.ipconf.me/api/ip/${ip}`);
  const data = await r.json();
  cache.set(ip, data);
  return data;
}

Handling VPN, proxy, and CDN users

A noticeable fraction of your traffic will be VPN or proxy users. Their geolocation will be the VPN's exit node, not their real location. For features that affect them (region-blocked content, geo-pricing, "your local store"), give an explicit override — never trap a user behind wrong geo with no escape.

Behind a CDN like Cloudflare, your origin sees the CDN edge IP. Read `CF-Connecting-IP` or `X-Forwarded-For` and look up that one instead. Otherwise every visitor looks like they're in San Francisco.

// Python (Flask example):
from flask import request
import requests

def visitor_geo():
    ip = (
        request.headers.get("CF-Connecting-IP")
        or request.headers.get("X-Forwarded-For", "").split(",")[0].strip()
        or request.remote_addr
    )
    r = requests.get(f"https://api.ipconf.me/api/ip/{ip}", timeout=2)
    return r.json() if r.ok else None

Privacy and GDPR

In the EU and several other jurisdictions, an IP address combined with other data is personal data. The act of looking up geolocation is generally fine; storing the result alongside a user account changes the analysis.

Practical rules: store only the fields you actually need, don't persist precise lookups indefinitely, document the processing in your privacy policy, and offer a way to disable location-aware features. Treat geo as a soft hint, not an identity claim.

Code examples in other languages

The API is just HTTP + JSON, so any language works. Below are minimal examples in Python and Go. Add your own timeouts, retries, and caching according to the patterns in the previous sections.

# Python (requests):
import requests
r = requests.get("https://api.ipconf.me/api/ip/1.1.1.1", timeout=2)
print(r.json()["country"])

# Go (net/http):
package main

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

func main() {
  r, _ := http.Get("https://api.ipconf.me/api/ip/1.1.1.1")
  defer r.Body.Close()
  var data map[string]any
  json.NewDecoder(r.Body).Decode(&data)
  fmt.Println(data["country"])
}