Suggest a country from a visitor's IP address

Suggest a visitor's country with IP geolocation and keep their own regional preference in control.

JavaScript (browser)Last tested Download and run ↓
On this page

Working example

HTML + JavaScript

Run the example

Download HTML

suggest-country-from-ip.html

Replace YOUR_PUBLIC_API_KEY in the downloaded file with your public key. Add localhost to that key's allowed domains. In a terminal in the download folder, run:

Terminal · Python 3
python3 -m http.server 8000

Open localhost:8000/suggest-country-from-ip.html. When publishing, add your website's hostname to the key. Keep secret keys on your server.

Need a key? Set up this example

Get the visitor's country

Use IP geolocation to suggest a country for a regional storefront or country picker. Call /ip from the browser to look up that visitor's connection and receive a two-letter country code, such as US.

JavaScript
async function suggestCountry(signal) {
  const url = new URL('https://api.parseapi.com/ip');
  url.search = new URLSearchParams({ key: API_KEY });
  const response = await fetch(url, { headers: { 'Parse-Version': '2.0.0' }, signal, cache: 'no-store', redirect: 'error' });
  if (!response.ok) throw new Error('Country lookup failed.');
  const data = await response.json();
  return typeof data?.country === 'string' && /^[A-Z]{2}$/.test(data.country)
    ? data.country : null;
}

The working example runs on load and displays the country. Refresh repeats the lookup. It uses Intl.DisplayNames to turn the code into a readable name without another API request.

Use it as a default

suggestCountry() returns a country code or null. Use the code wherever your app needs a regional suggestion. If the country is unknown or the request fails, keep your existing default.

Check for a saved preference before applying the suggestion. Once the visitor chooses a country, keep their choice through later refreshes and page loads. A VPN, corporate network, or travel can change the connection's country, so do not use it to infer nationality, residence, language, or a shipping destination. The lookup does not request device-location permission.

For a server-side integration, call /ip/{ip} with the visitor's IP from your framework's trusted request information. A bare /ip call from your server looks up the server's connection. See the IP API reference for the response fields and request options.

Complete example

One HTML file with the markup, styles, and JavaScript. Replace YOUR_PUBLIC_API_KEY with your public key, then run it on a domain you have added to that key.

View and copy the complete source
suggest-country-from-ip.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Suggest a country from a visitor's IP address</title>
  <style>
    :root { color-scheme: light dark; --bg: #fff; --ink: #152029; --muted: #5e6b75; --line: #d9e2e7; --field: #f6f9fa; --accent: #007c91; }
    @media (prefers-color-scheme: dark) {
      :root:not([data-theme="light"]) { --bg: #0b1015; --ink: #eff7fa; --muted: #94a6b2; --line: #2c3942; --field: #121b23; --accent: #67e8f9; }
    }
    :root[data-theme="dark"] { color-scheme: dark; --bg: #0b1015; --ink: #eff7fa; --muted: #94a6b2; --line: #2c3942; --field: #121b23; --accent: #67e8f9; }
    :root[data-theme="light"] { color-scheme: light; }
    * { box-sizing: border-box; }
    body { margin: 0; padding: 24px; background: var(--bg); color: var(--ink); font: 15px/1.5 system-ui, sans-serif; }
    main { max-width: 540px; margin: 0 auto; }
    h1 { margin: 0; color: var(--muted); font-size: 14px; font-weight: 500; }
    #country { margin: 8px 0; font-size: 28px; font-weight: 600; line-height: 1.25; overflow-wrap: anywhere; }
    #status { margin: 0; color: var(--muted); font-size: 13px; }
    button { margin-top: 20px; padding: 10px 14px; border: 1px solid var(--line); border-radius: 8px; background: var(--field); color: var(--accent); font: inherit; cursor: pointer; }
    button:disabled { opacity: .6; cursor: wait; }
    :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
    @media (max-width: 380px) { body { padding: 18px; } }
  </style>
</head>
<body>
  <main>
    <h1>Suggested country</h1>
    <div aria-live="polite" aria-atomic="true">
      <p id="country">Looking up your country...</p>
      <p id="status">Based on your internet connection.</p>
    </div>
    <button id="refresh" type="button">Refresh</button>
  </main>
  <script>
    const API_KEY = 'YOUR_PUBLIC_API_KEY';
    const country = document.querySelector('#country');
    const status = document.querySelector('#status');
    const refresh = document.querySelector('#refresh');
    const countryNames = new Intl.DisplayNames(['en'], { type: 'region' });
    let activeRequest;

    // example:request
    async function suggestCountry(signal) {
      const url = new URL('https://api.parseapi.com/ip');
      url.search = new URLSearchParams({ key: API_KEY });
      const response = await fetch(url, { headers: { 'Parse-Version': '2.0.0' }, signal, cache: 'no-store', redirect: 'error' });
      if (!response.ok) throw new Error('Country lookup failed.');
      const data = await response.json();
      return typeof data?.country === 'string' && /^[A-Z]{2}$/.test(data.country)
        ? data.country : null;
    }
    // /example:request

    async function refreshCountry() {
      activeRequest?.abort();
      const request = new AbortController();
      activeRequest = request;
      const timeout = setTimeout(() => request.abort(), 5000);
      refresh.disabled = true;
      country.textContent = 'Looking up your country...';
      status.textContent = 'Based on your internet connection.';
      try {
        const code = await suggestCountry(request.signal);
        if (activeRequest !== request) return;
        if (request.signal.aborted) throw new Error('Country lookup timed out.');
        country.textContent = code ? countryNames.of(code) : 'Country unknown';
        status.textContent = code
          ? `${code} · Based on your internet connection.`
          : 'Your connection did not return a country.';
      } catch {
        if (activeRequest !== request) return;
        country.textContent = 'Country unavailable';
        status.textContent = 'Could not look up your country. Try again.';
      } finally {
        clearTimeout(timeout);
        if (activeRequest === request) refresh.disabled = false;
      }
    }

    refresh.addEventListener('click', refreshCountry);
    refreshCountry();
  </script>
</body>
</html>

Need a key? Set up this browser example. For every field and parameter, see IP API reference.