How to get visitor's location (i.e. country) using geolocation? [closed]
Asked Answered
F

12

157

I'm trying to extend the native geolocation function

if(navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position) {
        var latitude = position.coords.latitude;
        var longitude = position.coords.longitude;
    });
}

so that I can use the visitor's country name (perhaps return an informative array).

So far all I've been able to find are functions that display a google maps interface but none actually gave what I want, except for this library which worked well in this example but for some reason didn't work on my computer. I'm not sure why that went wrong there.

Anyways, do you know how I can simply return an array containing information like country, city, etc. from latitude and longitude values?

Forbidden answered 15/8, 2010 at 22:2 Comment(5)
$.get("https://api.ipdata.co", function (response) { $("#response").html(JSON.stringify(response, null, 4)); }, "jsonp");Schoolmistress
See the fiddle jsfiddle.net/6wtf0q4gSchoolmistress
A quick disclaimer, I built the above service ipdata.co, it's also extremely scalable with 10 global endpoints each able to handle >800M calls daily!Schoolmistress
@SamuelLiew I don't believe the duplicate in this case is valid. This question specifically asks about geolocation, whereas the duplicate asks about locale, a similar but distinct question (as locale does not include lat & long, city, etc.).Fibrous
doesn't seem to work anymore @jonathanHevesy
N
82

You don't need to locate the user if you only need their country. You can look their IP address up in any IP-to-location service (like maxmind, ipregistry or ip2location). This will be accurate most of the time.

Here is a client-side example with Ipregistry (disclaimer, I am working for):

fetch('https://api.ipregistry.co/?key=tryout')
    .then(function (response) {
        return response.json();
    })
    .then(function (payload) {
        console.log(payload.location.country.name + ', ' + payload.location.city);
    });

If you really need to get their location, you can get their lat/lng with that method, then query Google's or Yahoo's reverse geocoding service.

Nectareous answered 20/8, 2010 at 6:2 Comment(7)
@juanpastas you don't. you just ping a service, and service will know. or you write service yourself, but that's out of pure javascript scope.Malikamalin
but to ping a service, that would be in server side? do you know a way to do that from client?Desiraedesire
What if I access the internet via a proxy in a different country?Randazzo
ipregistry.co is more generous than other alternatives. it has a free tier of 100k API calls, registration is simple and doesn't require entering credit card.Barrettbarrette
Nice recommendation, I tried ipregistry and the info is pretty straightforward.Secondguess
Excellent answerRegistrar
Be careful with such calls. The service may read information from your request, which means you should better check if this is compatible with your data protection rules.Encounter
L
233

You can use my service, http://ipinfo.io, for this. It will give you the client IP, hostname, geolocation information (city, region, country, area code, zip code etc) and network owner. Here's a simple example that logs the city and country:

$.get("https://ipinfo.io", function(response) {
    console.log(response.city, response.country);
}, "jsonp");

Here's a more detailed JSFiddle example that also prints out the full response information, so you can see all of the available details: http://jsfiddle.net/zK5FN/2/

The location will generally be less accurate than the native geolocation details, but it doesn't require any user permission.

Letitialetizia answered 30/7, 2013 at 12:33 Comment(25)
This does not work for me, when I request data, i get the full website as my response. Is there a better service to call maybe?Chas
You can force a json response by adding /json to the url. What are you making the request with though? It should automatically detect that you want json.Letitialetizia
@BenDowling: Please give the code in pure native Javascript (without jQuery). Many pages onload need to use without jQuery your method.Arbitress
But it doesn't support sites with "https". That's so sad.Eclogite
The result I got was way off the mark. I was browsing from Bangalore and it says that I am from Noida, Uttar Pradesh. Which is off by some 2112 kms.Dandify
1. This doesn't work on sites with https 2. This is free only upto 1000 hits per dayHifalutin
Yes it does work with https - it didn't used to, but does nowLetitialetizia
able to support high loads?Ki
It handles over 250 million requests a day, so definitely. It's free for up to 1,000 req/day, see ipinfo.io/pricing to plans beyond thatLetitialetizia
Works great on Fiddle! How would I add this to a Wordpress site?Estafette
Note that from the pricing page: > If you need to make under 1,000 requests a day to our API and it's for non-commerical use, or you just want to test things out, signup for the free plan. Otherwise select one of the paid plans below. - ipinfo.io/pricingLolalolande
how to get full name of conutryAronarondel
Here's how you get full country names from the country codes that the API returns: ipinfo.io/developers/full-country-namesLetitialetizia
I have made 3-5 requests and get message: "Upgrade to increase your usage limits at ipinfo.io/pricing" :(Scratches
@DamjanPavlica are you making them from "localhost" or something like that? Lots of other people will be too :) You can get a free access token to make 50k req / month.Letitialetizia
there is a pity that there is no ISO 3 country code in the reponse, so we should try to find a way to transform 2letter in 3 letter country codeSafir
You can transform the ISO2 code to ISO3 with the data downloads at country.io/dataLetitialetizia
Instead of answering a technical question, you are advertising your company, wtf? Every SO question can be answered this way. : "Call us and talk to our consultants"Tailwind
too bad this is blocked by the easylist/easyprivacy list by adblockers - otherwise i would have used itEnact
This is not an answer. This is an ad.Navarre
Ad or not, it solved my problem for me for free, and I get upto 50k requests. So +1, and thank you!Inhabiter
*requests per monthInhabiter
Its giving incorrect location for my IPOconnor
@Eatsamulhaq can you share details and I can investigate? Either here or email [email protected]Letitialetizia
@BenDowling I am located in Sahiwal city while the code is giving Lahore City. I have made no changes in the code and just run Js Fiddle code. I think there might be no record for "small cities"Oconnor
D
102

You can do this natively wihtout relying on IP services. You can get the user's timezone like this:

Intl.DateTimeFormat().resolvedOptions().timeZone

and then extract the country from that value. Here is a working example on CodePen.

Desdee answered 26/1, 2022 at 22:10 Comment(21)
That's a really interesting way to do it. I feel like there must be something wrong with it, but I can't think of a reason why. My first thought was time zones that span countries, but you seem to have that covered by including the linked time zones. This would, in theory, still get the right country even if the user is using VPN. The only downside is having to update your list of time zones when they change.Faxan
Thanks! Yeah, I'm unsure how reliable this is in a production environment, but it seems to be good enough for most cases. I confess I haven't tested this solution in larger projects, therefore I would recommend caution when doing so. I reckon that it would be possible to implement some logic to handle timezone nuances as well.Desdee
I tried it in the UK and worked!Punt
It seems like you can test it by changing the timezone on your computer. This works on my Macbook anyway.Salop
This is truly nice and everything, but what about Server-Side Rendring? I won't work there. Like, let's say I have a website with different languages, and I want to send back an html with the right language, based on the user's location. I don't want to have to do 2 trips for that.Guadalcanal
@TalKohavy well, you'll need the client's information either way to get their location, so it wouldn't be difficult to develop some solution for Node.js using this.Desdee
@DiegoFortes Not neccesarily my friend. Consider the case I mentioned once again, by typing in the webite's url and hitting Enter, the client provides nothing but an ip + cookie. The cookie is sent from the second time onwards (considering i'm using cookies in my website), while the ip is provided from the first time onwards. What you are suggesting is CSR, while I want SSR.Guadalcanal
I was checking this question for just research and I find this the most impressive answer!Favourable
I tested this code on Windows + Chrome/Edge/Firefox. It works everywhere!Helpmeet
really nice solution, but no sure about delivering of extra 2000 lines of js code to the browser, maybe the better option is to use some extrenal serviceEstas
@Estas naturally it's just one of the many options out there, it is not the axiom of getting users' locations. Developers may improve or disregard it as they seem fit. It's crucial to bear in mind that even with the 2000+ lines of code it's still faster than an API call, 100% reliable and it doesn't cost anything. Furthermore the 2000+ lines is simply a JSON object, that is very unlikely to have any meaningful impact on the website's performance.Desdee
A good alternative to IP geolocation services. Would not hurt to have some fallback, if you decide to take this code to production.B
Who maintains the database? Is there a central authority that can be relied on to update the database?Moorhead
@BillyMitchell more information about the Intl object can be found here.Desdee
Wow... Worked Perfect...This answer deserves lots of upvotes..... :)Ordinarily
I'm not in Singapore.Mouthy
@Mouthy as aforementioned, this is not a flawless solution. It grabs your device's timezone and translates to what country is most likely that you're in. Also if you setup your device's timezone to UTC, it will return null. If you require precision, you ought to use a third party IP serviceDesdee
@DiegoFortes I get it. Well US and Mexico and Canada overlaps a lot in TimeZones. I think this solution is useless my friend.Mouthy
@BillyMitchell Found databases containing the mappings here: iana.org/time-zones download "Data only", then look into zone.tab and iso3166.tab.Typify
Same solution but using moment-timezone ! Without using geoloc or IP lookup APIs (are free for dev use only) Using Intl.DateTimeFormat().resolvedOptions().timeZone and file extracted from moment-timezone Link to demo (stackblitz.com/edit/js-azokeh?file=index.js), you can download a file.Neology
great response for country lookup. I wouldn't use this for sstate lookup though, i live in a state that's in the wrong timezone (massachusetts), thinks i'm in new yorkMurk
N
82

You don't need to locate the user if you only need their country. You can look their IP address up in any IP-to-location service (like maxmind, ipregistry or ip2location). This will be accurate most of the time.

Here is a client-side example with Ipregistry (disclaimer, I am working for):

fetch('https://api.ipregistry.co/?key=tryout')
    .then(function (response) {
        return response.json();
    })
    .then(function (payload) {
        console.log(payload.location.country.name + ', ' + payload.location.city);
    });

If you really need to get their location, you can get their lat/lng with that method, then query Google's or Yahoo's reverse geocoding service.

Nectareous answered 20/8, 2010 at 6:2 Comment(7)
@juanpastas you don't. you just ping a service, and service will know. or you write service yourself, but that's out of pure javascript scope.Malikamalin
but to ping a service, that would be in server side? do you know a way to do that from client?Desiraedesire
What if I access the internet via a proxy in a different country?Randazzo
ipregistry.co is more generous than other alternatives. it has a free tier of 100k API calls, registration is simple and doesn't require entering credit card.Barrettbarrette
Nice recommendation, I tried ipregistry and the info is pretty straightforward.Secondguess
Excellent answerRegistrar
Be careful with such calls. The service may read information from your request, which means you should better check if this is compatible with your data protection rules.Encounter
M
38

You can use your IP address to get your 'country', 'city', 'isp' etc...
Just use one of the web-services that provide you with a simple api like http://ip-api.com which provide you a JSON service at http://ip-api.com/json. Simple send a Ajax (or Xhr) request and then parse the JSON to get whatever data you need.

var requestUrl = "http://ip-api.com/json";

$.ajax({
  url: requestUrl,
  type: 'GET',
  success: function(json)
  {
    console.log("My country is: " + json.country);
  },
  error: function(err)
  {
    console.log("Request failed, error= " + err);
  }
});
Mortie answered 21/3, 2016 at 12:10 Comment(2)
Since ip-api.com do not support https request, most browser will reject the request if called from within an https content/page. Plus, as per their website, > You are free to use ip-api.com for non-commercial use. We do not allow commercial use without prior approval.Lolalolande
ip-api is just one example of different services that provide IP-Location service. The question doesn't ask about https protocols. If you do use https web site I'm sure you could implement the same logic, just with a different IP-Location service.Mortie
S
15

See ipdata.co a service I built that is fast and has reliable performance thanks to having 10 global endpoints each able to handle >10,000 requests per second!

This answer uses a 'test' API Key that is very limited and only meant for testing a few calls. Signup for your own Free API Key and get up to 1500 requests daily for development.

This snippet will return the details of your current ip. To lookup other ip addresses, simply append the ip to the https://api.ipdata.co?api-key=test url eg.

https://api.ipdata.co/1.1.1.1?api-key=test

The API also provides an is_eu field indicating whether the user is in an EU country.

$.get("https://api.ipdata.co?api-key=test", function (response) {
    $("#response").html(JSON.stringify(response, null, 4));
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="response"></pre>

Here's the fiddle; https://jsfiddle.net/ipdata/6wtf0q4g/922/

I also wrote this detailed analysis of 8 of the best IP Geolocation APIs.

Schoolmistress answered 6/11, 2017 at 11:19 Comment(3)
That is false. The service is free up to 45,000 requests a month. Smallest plan is $10 and the error mentioned is returned to prevent abuse. Note that it is also accompanied by an email to warn you you've exhausted all your requests.Schoolmistress
My comment is not falseGalleywest
Your comment is inherently false and misleading.Schoolmistress
T
13

A very easy to use service is provided by ws.geonames.org. Here's an example URL:

http://ws.geonames.org/countryCode?lat=43.7534932&lng=28.5743187&type=JSON

And here's some (jQuery) code which I've added to your code:

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position) {
        $.getJSON('http://ws.geonames.org/countryCode', {
            lat: position.coords.latitude,
            lng: position.coords.longitude,
            type: 'JSON'
        }, function(result) {
            alert('Country: ' + result.countryName + '\n' + 'Code: ' + result.countryCode);
        });
    });
}​

Try it on jsfiddle.net ...

Tut answered 31/7, 2012 at 16:49 Comment(3)
geolocation no longer works over http, and that service is unavailable over httpsBriquet
They have https endpoint: secure.geonames.org forum.geonames.org/gforum/posts/list/34294.pagePowers
This is the only one that answers the actual question.Delmardelmer
P
8

A free and easy to use service is provided at Webtechriser (click here to read the article) (called wipmania). This one is a JSONP service and requires plain javascript coding with HTML. It can also be used in JQuery. I modified the code a bit to change the output format and this is what I've used and found to be working: (it's the code of my HTML page)

<html>
    <body>
        <p id="loc"></p>


        <script type="text/javascript">
            var a = document.getElementById("loc");

  	            function jsonpCallback(data) { 
	            a.innerHTML = "Latitude: " + data.latitude + 
                              "<br/>Longitude: " + data.longitude + 
                              "<br/>Country: " + data.address.country; 
 	            }
        </script>
        <script src="http://api.wipmania.com/jsonp?callback=jsonpCallback"
                     type="text/javascript"></script>


    </body>
</html>

PLEASE NOTE: This service gets the location of the visitor without prompting the visitor to choose whether to share their location, unlike the HTML 5 geolocation API (the code that you've written). Therefore, privacy is compromised. So, you should make judicial use of this service.

Paoting answered 21/5, 2016 at 9:27 Comment(3)
I see 0 for Latitude and Longitude and Unknown for Country over here on stack overflow but it worked when I used it in a HTML webpage.Paoting
I've just used this on a very old site of mine and I'm please to say it works: e-artlab.com/about-you - although not on all platforms or browsers (on my partner's Win/Edge and Win/Chrome access is blocked, although my Mac/Chrome is fine)?Schaffhausen
Insecure connection as using HTTP.Marbles
R
7

I wanted to localize client side pricing for few countries without using any external api, so I used local Date object to fetch the country using new Date()).toString().split('(')[1].split(" ")[0]

    document.write((new Date()).toString().split('(')[1].split(" ")[0])

Basically this small code snippet extracts the first word from Date object. To check for various time zone, you can change the time of your local machine.

In my case, our service only included three countries, so I was able to get the location using the following code.

const countries = ["India", "Australia", "Singapore"]
const countryTimeZoneCodes = {
  "IND": 0,
  "IST": 0,
  "AUS": 1,
  "AES": 1,
  "ACS": 1,
  "AWS": 1,
  "SGT": 2,
  "SIN": 2,
  "SST": 2
} // Probable three characters from timezone part of Date object
let index = 0
try {
  const codeToCheck = (new Date()).toString().split('(')[1].split(" ")[0].toUpperCase().substring(0, 3)
  index = countryTimeZoneCodes[codeToCheck]

} catch (e) {

  document.write(e)
  index = 0
}

document.write(countries[index])

This was just to improve user experience. It's not a full proof solution to detect location. As a fallback for not detecting correctly, I added a dropdown in the menubar for selecting the country.

Rambow answered 11/6, 2021 at 9:28 Comment(3)
This is just to improve user experience, insted of asking new user to select country from dropdown, we can provide auto selection for few. And for your eastern part, either you are from US or Canada. Refer en.wikipedia.org/wiki/Eastern_Time_ZoneRambow
This is not working on my end.Desdee
this is not working for meRochkind
G
4

For developers looking for a full-featured geolocation utility, you can have a look at geolocator.js (I'm the author).

Example below will first try HTML5 Geolocation API to obtain the exact coordinates. If fails or rejected, it will fallback to Geo-IP look-up. Once it gets the coordinates, it will reverse-geocode the coordinates into an address.

var options = {
    enableHighAccuracy: true,
    timeout: 6000,
    maximumAge: 0,
    desiredAccuracy: 30,
    fallbackToIP: true, // if HTML5 geolocation fails or rejected
    addressLookup: true, // get detailed address information
    timezone: true, 
    map: "my-map" // this will even create a map for you
};

geolocator.locate(options, function (err, location) {
    console.log(err || location);
});

It supports geo-location (via HTML5 or IP lookups), geocoding, address look-ups (reverse geocoding), distance & durations, timezone information and more...

Googins answered 1/7, 2016 at 23:19 Comment(2)
works like a charm! However, you need to enable multiple APIs on google to make it work. Had to enable Google Maps Time Zone API and Google Maps Geocoding API. Adding it to documentation could save user some more time :). Thanks!Mallemuck
Geolocator has a detailed documentation here: onury.github.io/geolocator/?api=geolocator Thanks.Angular
A
4

You can simply import in your app.component.ts or whichever component you want to use

import { HttpClient } from '@angular/common/http';

Then make a simple GET request to http://ip-api.com/json

  getIPAddress() {
    this.http.get("http://ip-api.com/json").subscribe((res: any) => {
      console.log('res ', res);
    })
  }

You will get the following response by using it:

{
    "status": "success",
    "country": "country fullname here",
    "countryCode": "country shortname here",
    "region": "region shortname here",
    "regionName": "region fullname here",
    "city": "city fullname here",
    "zip": "zipcode will be in string",
    "lat": "latitude here will be in integer",
    "lon": "logitude here will be in integer",
    "timezone": "timezone here",
    "isp": "internet service provider name here",
    "org": "internet service provider organization name here",
    "as": "internet service provider name with some code here",
    "query": "ip address here"
}
Apogee answered 22/6, 2022 at 18:51 Comment(0)
D
2

You can use ip-api.io to get visitor's location. It supports IPv6.

As a bonus it allows to check whether ip address is a tor node, public proxy or spammer.

JavaScript Code:

function getIPDetails() {
    var ipAddress = document.getElementById("txtIP").value;

    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            console.log(JSON.parse(xhttp.responseText));
        }
    };
    xhttp.open("GET", "http://ip-api.io/json/" + ipAddress, true);
    xhttp.send();
}

<input type="text" id="txtIP" placeholder="Enter the ip address" />
<button onclick="getIPDetails()">Get IP Details</button>

jQuery Code:

$(document).ready(function () {
        $('#btnGetIpDetail').click(function () {
            if ($('#txtIP').val() == '') {
                alert('IP address is reqired');
                return false;
            }
            $.getJSON("http://ip-api.io/json/" + $('#txtIP').val(),
                 function (result) {
                     alert('Country Name: ' + result.country_name)
                     console.log(result);
                 });
        });
    });

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div>
    <input type="text" id="txtIP" />
    <button id="btnGetIpDetail">Get Location of IP</button>
</div>
Disassemble answered 29/7, 2017 at 13:55 Comment(3)
Be good to also include an example in straight JavaScript, anyone not using JQuery :-)Schaffhausen
Thanks @DaveEveritt ! I have added JavaScript code also.Disassemble
Others gave this answer before you + It won't work on HTTPS websites, because your webbrowser won't allow calls to http://... because they are unsecure.Atalie
C
1

If you don't want to use an api and only the country is enough for you, you can use topojson and worldatlas.

import { feature } from "https://cdn.skypack.dev/[email protected]";
import { geoContains, geoCentroid, geoDistance } from "https://cdn.skypack.dev/[email protected]";

async function success(position) {
    const topology = await fetch("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-50m.json").then(response => response.json());
    const geojson = feature(topology, topology.objects.countries);
    
    const {
        longitude,
        latitude,
    } = position.coords;
    
    const location = geojson.features
        .filter(d => geoContains(d, [longitude, latitude]))
        .shift();
    
    if (location) {
        document.querySelector('#location').innerHTML = `You are in <u>${location.properties.name}</u>`;
    }
    
    if (!location) {
        const closestCountry = geojson.features
            // You could improve the distance calculation so that you get a more accurate result
            .map(d => ({ ...d, distance: geoDistance(geoCentroid(d), [longitude, latitude]) }))
            .sort((a, b) => a.distance - b.distance)
            .splice(0, 5);
        
        if (closestCountry.length > 0) {
            const possibleLocations = closestCountry.map(d => d.properties.name);
            const suggestLoctions = `${possibleLocations.slice(0, -1).join(', ')} or ${possibleLocations.slice(-1)}`;
            
            document.querySelector('#location').innerHTML = `It's not clear where you are!<section>Looks like you are in ${suggestLoctions}</section>`;
        }
        
        if (closestCountry.length === 0) {
            error();
        }        
    }
}

function error() {
    document.querySelector('#location').innerHTML = 'Sorry, I could not locate you';
};

navigator.geolocation.getCurrentPosition(success, error);

This code takes longitude and latitude and checks if this point is included in one of the geojson's feature (a spatially bounded entity). I created also a working example.

Centesimal answered 25/11, 2021 at 9:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.