User Location

There are two ways to detect user's location -

Geo Location

The HTML Geolocation API is used to locate a user's position. The Geolocation API allows the user to provide their location to web applications if they so desire. For privacy reasons, the user is asked for permission to report location information.

The Geolocation API is published through the navigator.geolocation object. You can check if the browser supports this API with the following code :

if ("geolocation" in navigator) {
  /* geolocation is available */
} else {
  /* geolocation IS NOT available */
}

Getting the current position

To obtain the user's current location, you can call the getCurrentPosition() method. This initiates an asynchronous request to detect the user's position, and queries the positioning hardware to get up-to-date information. When the position is determined, the defined callback function is executed. You can optionally provide a second callback function to be executed if an error occurs. A third, optional, parameter is an options object where you can set the maximum age of the position returned, the time to wait for a request, and if you want high accuracy for the position.

navigator.geolocation.getCurrentPosition(callback);

Here is an example -

console.log("Getting Position");
navigator.geolocation.getCurrentPosition(function(position) {
  console.log(position);
});
function getLocation(){
	console.log("Getting Position");
	navigator.geolocation.getCurrentPosition(function(position) {
	  console.log(position);
	  let output = document.getElementById("Result");
	  output.innerHTML += "<p style='margin: 0;'>Latitude = " + position.coords.latitude+"</p>";
	  output.innerHTML += "<p style='margin: 0;'>Longitude = " + position.coords.longitude+"</p>";
	});
}

The second parameter of the getCurrentPosition() method is used to handle errors. It specifies a function to run if it fails to get the user's location. It expects a PositionError object as its first parameter.

function showError(error) {
  switch(error.code) {
    case error.PERMISSION_DENIED:
      console.log("User denied the request for Geolocation.");
      break;
    case error.POSITION_UNAVAILABLE:
      console.log("Location information is unavailable.");
      break;
    case error.TIMEOUT:
      console.log("The request to get user location timed out.");
      break;
    case error.UNKNOWN_ERROR:
      console.log("An unknown error occurred.");
      break;
  }
}

Accurate Result

This methods accepts last argument which is options, which you can use for some configuration. To get more accurate result set the enableHighAccuracy property to true.

var options = {
  enableHighAccuracy: true,
  timeout: 5000,
  maximumAge: 0
};
function error(err) {
  console.warn(`ERROR(${err.code}): ${err.message}`);
}
function getLocation(){
	navigator.geolocation.getCurrentPosition(function(position) {
		console.log(position);
	}, error, options);
}

Getting Location using Latitude and Longitude

To get user's location using Latitude and Longitude, you can use an external service. Like Google's Map API:

First add the script:

<script src="https://maps.googleapis.com/maps/api/js?key=YourAPIKey&libraries=places" async defer></script>
// Get the Coordinates using HTML5 GeoLocation feature -
var options = {
  enableHighAccuracy: true,
  timeout: 5000,
  maximumAge: 0
};
function error(err) {
  console.warn(`ERROR(${err.code}): ${err.message}`);
}
function getLocation(){
	navigator.geolocation.getCurrentPosition(function(position) {
		convertToAddress(position);
	}, error, options);
}

// Then Convert the position to human redable location using Google Map API -
function convertToAddress(position){
	var geocoder  = new google.maps.Geocoder();
	var location  = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
	geocoder.geocode({'latLng': location}, function (results, status) {
		if(status == google.maps.GeocoderStatus.OK) {
			console.log(results);
			let Positions = new Set();
			results.forEach(function(item, index, array){
				item.address_components.forEach(function(item, index, array){
					if (Number(item.long_name)>0) {
					}else{
						Positions.add(item.long_name);
					}
				});
			});
			console.log(Positions);
		}
	});
}

IP Address

STUN IP Address requests for WebRTC

Firefox and Chrome have implemented WebRTC that allow requests to STUN servers be made that will return the local and public IP addresses for the user. These request results are available to javascript, so you can now obtain a users local and public IP addresses in javascript. This demo is an example implementation of that.

Additionally, these STUN requests are made outside of the normal XMLHttpRequest procedure, so they are not visible in the developer console or able to be blocked by plugins such as AdBlockPlus or Ghostery. This makes these types of requests available for online tracking if an advertiser sets up a STUN server with a wildcard domain.

Get User's Local IP

//get the IP addresses associated with an account
function getIPs(callback){
    var ip_dups = {};

    //compatibility for firefox and chrome
    var RTCPeerConnection = window.RTCPeerConnection
        || window.mozRTCPeerConnection
        || window.webkitRTCPeerConnection;
    var useWebKit = !!window.webkitRTCPeerConnection;

    //bypass naive webrtc blocking using an iframe
    if(!RTCPeerConnection){
        //NOTE: you need to have an iframe in the page right above the script tag
        //
        //<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe>
        //<script>...getIPs called in here...
        //
        var win = iframe.contentWindow;
        RTCPeerConnection = win.RTCPeerConnection
            || win.mozRTCPeerConnection
            || win.webkitRTCPeerConnection;
        useWebKit = !!win.webkitRTCPeerConnection;
    }

    //minimal requirements for data connection
    var mediaConstraints = {
        optional: [{RtpDataChannels: true}]
    };

    var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};

    //construct a new RTCPeerConnection
    var pc = new RTCPeerConnection(servers, mediaConstraints);

    function handleCandidate(candidate){
        //match just the IP address
        var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
        var ip_addr = ip_regex.exec(candidate)[1];

        //remove duplicates
        if(ip_dups[ip_addr] === undefined)
            callback(ip_addr);

        ip_dups[ip_addr] = true;
    }

    //listen for candidate events
    pc.onicecandidate = function(ice){

        //skip non-candidate events
        if(ice.candidate)
            handleCandidate(ice.candidate.candidate);
    };

    //create a bogus data channel
    pc.createDataChannel("");

    //create an offer sdp
    pc.createOffer(function(result){

        //trigger the stun server request
        pc.setLocalDescription(result, function(){}, function(){});

    }, function(){});

    //wait for a while to let everything done
    setTimeout(function(){
        //read candidate info from local description
        var lines = pc.localDescription.sdp.split('\n');

        lines.forEach(function(line){
            if(line.indexOf('a=candidate:') === 0)
                handleCandidate(line);
        });
    }, 1000);
}

//Test: Print the IP addresses into the console
getIPs(function(ip){console.log(ip);});

Get User's Public IP

function getPublicIPs(callback){
    var ip_dups = {};

    //compatibility for firefox and chrome
    var RTCPeerConnection = window.RTCPeerConnection
        || window.mozRTCPeerConnection
        || window.webkitRTCPeerConnection;
    var useWebKit = !!window.webkitRTCPeerConnection;

    //bypass naive webrtc blocking using an iframe
    if(!RTCPeerConnection){
        //NOTE: you need to have an iframe in the page right above the script tag
        //
        //<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe>
        //<script>...getIPs called in here...
        //
        var win = iframe.contentWindow;
        RTCPeerConnection = win.RTCPeerConnection
            || win.mozRTCPeerConnection
            || win.webkitRTCPeerConnection;
        useWebKit = !!win.webkitRTCPeerConnection;
    }

    //minimal requirements for data connection
    var mediaConstraints = {
        optional: [{RtpDataChannels: true}]
    };

    var servers = {iceServers: [{urls: "stun:stun.l.google.com:19302?transport=udp"}]};

    //construct a new RTCPeerConnection
    var pc = new RTCPeerConnection(servers, mediaConstraints);

    function handleCandidate(candidate){
        //match just the IP address
        var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
        var ip_addr = ip_regex.exec(candidate)[1];

        //remove duplicates
        if(ip_dups[ip_addr] === undefined)
            callback(ip_addr);

        ip_dups[ip_addr] = true;
    }

    //listen for candidate events
    pc.onicecandidate = function(ice){

        //skip non-candidate events
        if(ice.candidate)
            handleCandidate(ice.candidate.candidate);
    };

    //create a bogus data channel
    pc.createDataChannel("");

    //create an offer sdp
    pc.createOffer(function(result){

        //trigger the stun server request
        pc.setLocalDescription(result, function(){}, function(){});

    }, function(){});

    //wait for a while to let everything done
    setTimeout(function(){
        //read candidate info from local description
        var lines = pc.localDescription.sdp.split('\n');

        lines.forEach(function(line){
            if(line.indexOf('a=candidate:') === 0)
                handleCandidate(line);
        });
    }, 1000);
}

Okay, now you know how to get local and public IP of the User. To get user's location, we need public IP.

There are many online service available that takes IP as the input and returns the location. For example, GeoPlugin is one of the great online service which does this job.

http://www.geoplugin.net/json.gp?ip=xx.xx.xx.xx

For example:

http://www.geoplugin.net/json.gp?ip=14.195.239.254
See Location

Accuracy

Accuracy depends on many factors, some of which are beyond your control, and at best the location information returned by the API is just an approximation.

Most common use case. For the most part, HTML5 Geolocation works just fine in dense urban areas when you are stationary with your laptop or smartphone Wifi turned on. This is the use case most commonly cited when questions are asked about accuracy. This makes sense because urban areas have many public and private Wifi routers and cell phone towers are typically closer together. As you’ll see, HTML5 uses these and other methods to pinpoint your location. However, it’s not always that simple and below are some other use cases that you should take into consideration.

How does the API work? Depending on which browser you are using, the HTML5 Geolocation API approximates location based on a number of factors including your public IP address, cell tower IDs, GPS information, a list of Wifi access points, signal strengths and MAC IDs (Wifi and/or Bluetooth). It then passes that information to a Location Service usually via an HTTPS request which attempts to correlate your location from a variety of databases that include Wifi access point locations both public and private, as well as Cell Tower and IP address locations. An approximate location is then returned to your code via a JavaScript callback.

Consider the following:

function getLocation(){
	console.log("Getting Position");
	navigator.geolocation.getCurrentPosition(function(position) {
	  console.log(position);
	});
}

If you see the console, position includes coords.accuracy property. It's value is number which represents the radius in meters.

If the number is very high like greater than 10,000, it is very far from the user's location. The greater the number, the greater the inaccurate result. So If the accuracy number is very low, like below 1,000, it is nearly accurate result.

If you use WiFi network accuracy can be 5-50 meters, but you are using LAN. Geolocation by IP is very very inaccurate, it's normaly to get wrong city or country. Like above in the picture.

If you use mobile, you will get very accurate result as mobile devices uses GPS or other technology which helps to get accurate result.