How I managed to work around the getCurrentPosition (user location) JavaScript restriction on unsecured pages

Since April 2016, or Chrome version 50, Google deprecated the navigator.geolocation.getCurrentPosition feature on unsecured pages which lead many clients to rampage at project managers because of features on their website that rely heavily on this feature. Keep in mind this is a JavaScript feature that Google decided to block in order to protect their users privacy.

In my particular case a client came to me asking if I could deliver a solution to their Store Locator with the following features:

  • Show the distance from the current user location to the stores displaying on the map
  • Calculate the distance from the current user location to a specific store the user searched on the map.

The client told me other developers simply said there is no way to bypass this unless the client installed SSL certificate for his website. I did recommend getting an SSL Certificate as the best option and that Google is giving priority to websites with SSL but the client was still redundant.

So with an SSL Certificate looking to be the last option available i went to look for an alternative way to getting the current user location.
I ended up finding a service called ip-api.com that have a free API that can be used to get user information. Since we are dealing with JavaScript i’ll stick to the json version: ip-api.com/json

Check if the user is using Google Chrome and the website is not using HTTPS
So must have conditions, website not using https and user is on Google Chrome

If(location.protocol != 'https:') {
if(window.chrome) {
    var position = {
coords: {
latitude: '',
longitude: ''
}
};
  }
}

Although I know my client website currently doesn’t have https, in case it has someday, there will be no need do do this workaround and change the code. Also if the user it not using Google Chrome, which, at the moment is the only browser blocking this feature, there is not need to use this workaround.

If the website is HTTP and not HTTPS and the user is on Google Chrome than I start by creating an object with a similar structure to the object i get when using navigator.geolocation.getCurrentLocation(); This allows me to use the same function to handle the success and error responses, a simple DRY principle.

We need to query ip-api.com to get the user information, we do this by making an ajax request to the api. I am using jQuery for this.

$.getJSON(“http://ip-api.com/json", function (data, status) {
if(status === "success" ) {
//
}
});

The ip-api.com response includes a latitude and longitude but I found that it can miss the current user location by a too large of a distance to be considered, so I prefer to use the zip code if it is available.

$.getJSON(“http://ip-api.com/json", function (data, status) {
if(status === "success") {
if(data.zip) {}
}
});

If we are going with the zip code, we still need to get latitude and longitude coordinates. Since we are using google maps, I use the Google Maps Geocode API to query the zip code and get the GPS coordinates.

$.getJSON(“http://maps.googleapis.com/maps/api/geocode/json?address=" + res.zip, function (data, status) {
  if (status === "success") {
    position.coords.latitude = data.results[0].geometry.location.lat;
position.coords.longitude = data.results[0].geometry.location.lng;
locationOnSuccess(position);
  } else {
locationOnError();
}
});

When we get a success response from Google Geocode API we can assign the latitude and longitude coordinates to our object and pass it to our success function. Otherwise, when we get an error, we call our error handler function.

The success and error functions are simply two handlers I build to perform specific tasks. I won’t be including them since they don’t add anything to this article.

With this in mind we still need to handle with three other possible scenarios:

  1. The ip-api.com response did not retrieve a zip code
  2. The ip-api.com request returned an error
  3. The user browser can use navigator.geolocation.getCurrentPosition()

Here is the final code:

If(location.protocol != 'https:') {
if(window.chrome) {
var position = {
coords: {
latitude: '',
longitude: ''
}
};
$.getJSON(“http://ip-api.com/json", function (data, status) {
if(status === "success") {
if(data) {
$.getJSON(“http://maps.googleapis.com/maps/api/geocode/json?address=" + res.zip, function (data, status) {
if (status === "success") {
position.coords.latitude = data.results[0].geometry.location.lat;
position.coords.longitude = data.results[0].geometry.location.lng;
locationOnSuccess(position);
} else {
locationOnError();
}
});
} else {
if(!data.zip && data.lat && data.lon) {
//if there's not zip code but we have a latitude and longitude, let's use them
position.coords.latitude = data.lat;
position.coords.longitude = data.lon;
locationOnSuccess(position);
} else {
//if there's an error
locationOnError();
}
}
} else {
locationOnError();
}
});
} else {
navigator.geolocation.getCurrentPosition(locationOnSuccess, locationOnError, geo_options);
}
} else {
navigator.geolocation.getCurrentPosition(locationOnSuccess, locationOnError, geo_options);
}

This is a quick and simple workaround I found while trying to solve a common issue in the shortest amount of time. If you have an alternative I would love to hear about it.