I switched from ip-api.com to a zero-key API — here's why (HTTPS, CORS, no rate limits)

javascript dev.to

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
Enter fullscreen mode Exit fullscreen mode

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
  });
Enter fullscreen mode Exit fullscreen mode
Fullresponseschema:{"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"}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

Python (server-side)

pythonimport requests

data = requests.get('https://ippubblico.org/?api=1').json()
print(data['country'])   # Italy
print(data['isp'])       # Telecom Italia
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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.

Source: dev.to

arrow_back Back to Tutorials