f you've ever tried to use ip-api.com on an HTTPS site, you've hit this error:
"Mixed Content: The page was loaded over 'https', but requested an insecure resource 'http://ip-api.com/json'. This request has been blocked."
ip-api.com is the most cited free geolocation API on the internet — Stack Overflow answers, tutorials, GitHub gists. It's genuinely good. But its free tier only supports HTTP, which means it silently breaks on any HTTPS page. Browsers block it. No fallback, no warning in your code — it just fails.
I ran into this while building a feature that needed to show region-specific content. Here's what I found after testing several alternatives.
The problem in one line:
// This breaks silently on any HTTPS site
fetch('http://ip-api.com/json') // ❌ blocked by browser mixed-content policy
What I needed
- HTTPS endpoint (non-negotiable in 2026)
- No API key or signup
- CORS enabled (works directly from the browser)
- Returns country, city, ISP — not just the raw IP
- No commercial use restrictions
The solution I'm using:
// Works on HTTPS, no key, CORS enabled
fetch('https://ippubblico.org/?api=1')
.then(res => res.json())
.then(data => {
console.log(data.ip); // "93.56.x.x"
console.log(data.country); // "Italy"
console.log(data.countryCode); // "IT"
console.log(data.city); // "Rome"
console.log(data.isp); // "Telecom Italia"
console.log(data.timezone); // "Europe/Rome"
console.log(data.lat); // 41.9028
console.log(data.lon); // 12.4964
});
Full response schema:
{
"ip": "93.56.x.x",
"country": "Italy",
"countryCode": "IT",
"region": "Lazio",
"city": "Rome",
"zip": "00100",
"lat": 41.9028,
"lon": 12.4964,
"timezone": "Europe/Rome",
"isp": "Telecom Italia",
"asn": "AS3269"
}
Powered by a local MaxMind database — no external calls, fast response times.
Production-ready snippet with caching
Avoid calling the API on every page load — cache in sessionStorage:
async function getClientGeo() {
const cached = sessionStorage.getItem('_geo');
if (cached) return JSON.parse(cached);
try {
const res = await fetch('https://ippubblico.org/?api=1');
const data = await res.json();
sessionStorage.setItem('_geo', JSON.stringify(data));
return data;
} catch (e) {
return null;
}
}
// Usage
const geo = await getClientGeo();
if (geo?.countryCode === 'US') {
// show USD pricing
}
Python (server-side)
pythonimport requests
data = requests.get('https://ippubblico.org/?api=1').json()
print(data['country']) # Italy
print(data['isp']) # Telecom Italia
Bash / curl
bash# Plain IP
curl -s https://ippubblico.org/?text=1
# Full JSON
curl -s https://ippubblico.org/?api=1
# Extract country with jq
curl -s https://ippubblico.org/?api=1 | jq -r '.country'
Quick comparison
- ip-api.com — free but HTTP only, no key required, non-commercial use only
- ipify.org — HTTPS, no key, returns IP address only (no geolocation)
- ipinfo.io — HTTPS, key required, limited free tier
- ipstack.com — HTTPS only on paid tier, key required
- ippubblico.org — HTTPS, no key, no restrictions, full geolocation
Multilingual responses
One thing I didn't expect: the API supports 43 languages via the lang parameter.
javascriptfetch('https://ippubblico.org/?api=1&lang=it')
.then(res => res.json())
.then(data => console.log(data.country)); // "Italia"
Useful if you're building multilingual apps and want country names in the user's language without a translation layer.
API docs
Full documentation at https://ippubblico.org/docs.html — includes examples for curl, JavaScript, Python, PHP, and Dart.
Top comments (0)