Building an IP Address Query Tool: From API Calls to Geolocation Implementation
Building an IP Address Query Tool: From API Calls to Geolocation Implementation#
When developing web applications, you often need to get users’ IP addresses and geolocation information—for analytics, content delivery, fraud detection, and more. I recently built an IP query tool for a side project and documented the key implementation decisions.
How IP Geolocation Actually Works#
First, let’s clarify something: IP addresses don’t contain geographic information. IP geolocation works by querying IP address attribution databases built from:
- WHOIS data: Registration info when IPs are assigned to ISPs or organizations
- BGP routing tables: Inferring location from routing paths
- Crowdsourced data: Reverse calculation from WiFi/cell tower located users
Accuracy is limited—city-level is typical, street-level is unreliable.
Frontend Implementation: API Selection#
The core implementation is straightforward:
interface IpInfo {
ip: string
country?: string
region?: string
city?: string
isp?: string
timezone?: string
lat?: number
lon?: number
}
async function queryIpInfo(ip: string): Promise<IpInfo | null> {
try {
const response = await fetch(`https://ipapi.co/${ip}/json/`)
const data = await response.json()
if (data.ip) {
return {
ip: data.ip,
country: data.country_name,
region: data.region,
city: data.city,
isp: data.org,
timezone: data.timezone,
lat: data.latitude,
lon: data.longitude,
}
}
return null
} catch (e) {
console.error('IP query failed:', e)
return null
}
}
Why ipapi.co?#
Several IP geolocation APIs exist. Key selection criteria:
| API | Free Tier | HTTPS | Speed | Data Quality |
|---|---|---|---|---|
| ipapi.co | 1000/day | ✅ | Fast | High |
| ip-api.com | 45/min | ❌ (paid) | Fast | Medium |
| ipinfo.io | 50000/month | ✅ | Fast | Medium |
| ipgeolocation.io | 30000/month | ✅ | Medium | High |
ipapi.co provides free HTTPS support—essential for frontend calls. ip-api.com’s free tier lacks HTTPS, causing mixed content blocks in browsers.
Fetching Your Own IP#
To get the client’s current IP before querying others:
const fetchMyIp = async () => {
try {
const response = await fetch('https://ipapi.co/json/')
const data = await response.json()
setMyIp(data.ip)
} catch (e) {
console.error('Failed to fetch IP:', e)
}
}
No IP parameter needed—the server returns the client IP from the request.
Handling IPv4 and IPv6#
IPv6 adoption is growing. Basic validation:
// IPv4 format
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/
// IPv6 format (simplified)
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/
function validateIp(ip: string): boolean {
return ipv4Regex.test(ip) || ipv6Regex.test(ip)
}
Full IPv6 regex is complex due to shorthand forms (:: for consecutive zeros). Use a library like ip-regex in production.
Error Handling & User Experience#
Robust error handling is essential:
const handleQuery = async () => {
if (!ip.trim()) {
setError('Please enter an IP address')
return
}
setLoading(true)
setError('')
try {
const result = await queryIpInfo(ip)
if (result) {
setResult(result)
} else {
setError('Query failed. Please check the IP address format.')
}
} catch (e) {
setError('Network error. Please try again.')
} finally {
setLoading(false)
}
}
UX improvements:
- Enter key support:
onKeyDown={(e) => e.key === 'Enter' && handleQuery()} - Loading feedback: button shows “Querying…” and disables
- Specific error messages: distinguish format vs network errors
Performance & Rate Limiting#
Free APIs have rate limits. Consider these strategies:
1. Frontend Caching#
Cache results in localStorage:
const cacheKey = `ip-info-${ip}`
const cached = localStorage.getItem(cacheKey)
if (cached) {
setResult(JSON.parse(cached))
return
}
// After API call
localStorage.setItem(cacheKey, JSON.stringify(result))
2. Debouncing#
For real-time queries, debounce input:
import { debounce } from 'lodash'
const debouncedQuery = useMemo(
() => debounce((value: string) => {
if (validateIp(value)) {
handleQuery(value)
}
}, 500),
[]
)
3. Backend Proxy (Advanced)#
For high volume, use backend proxy + cache:
Client → Your Backend → IP API
↑
Redis Cache
This reduces API calls and hides your API key.
Privacy & Compliance#
IP addresses are personal data under GDPR. Best practices:
- Notify users: Clearly state IP collection
- Minimize data: Only collect what’s needed
- Protect data: Don’t store raw IPs
// Masking example
const maskIp = (ip: string) => {
return ip.replace(/(\d+\.\d+\.)\d+\.\d+/, '$1***.***')
}
// 192.168.1.100 → 192.168.***.***
Final Result#
Built an online tool based on these principles: IP Address Query
Features:
- Auto-detect your IP
- Query any IPv4/IPv6 address
- Display country, region, city, ISP, timezone, coordinates
- One-click detail lookup for your IP
Implementation isn’t complex, but getting the details right requires thoughtful API selection, error handling, performance optimization, and privacy compliance.
Related tools: IP Subnet Calculator | Port Checker