navigator.geolocation.getCurrentPosition sometimes works sometimes doesn't
Asked Answered
V

24

254

So I have a pretty simple bit of JS using the navigator.geolocation.getCurrentPosition jammy.

$(document).ready(function(){
  $("#business-locate, #people-locate").click(function() {
    navigator.geolocation.getCurrentPosition(foundLocation, noLocation);
  });

  navigator.geolocation.getCurrentPosition(foundLocation, noLocation);

  function foundLocation(position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    var userLocation = lat + ', ' + lon;
    $("#business-current-location, #people-current-location").remove();
    $("#Near-Me")
      .watermark("Current Location")
      .after("<input type='hidden' name='business-current-location' id='business-current-location' value='"+userLocation+"' />");
    $("#people-Near-Me")
      .watermark("Current Location")
      .after("<input type='hidden' name='people-current-location' id='people-current-location' value='"+userLocation+"' />");
  }
  function noLocation() {
    $("#Near-Me").watermark("Could not find location");
    $("#people-Near-Me").watermark("Could not find location");
  }
})//end DocReady

Basically what's happening here is we get the current position, if it's obtained, two "watermarks" are placed in two fields that say "Current Position" and two hidden fields are created with the lat-long data as their value (they're removed in the beginning so they don't get duplicated every time). There are also two buttons that have a click function tied to them that do the same thing. Unfortunately, every third time or so, it works. What's the problem here???

Viv answered 3/8, 2010 at 14:37 Comment(7)
Maybe define the functions before you use them.Radiancy
@digitalFresh, that shouldn't matter because the JS parser looks for those declarations before the code starts executionPic
Is it possible that the use of jQuery in there is causing problems?Viv
What exactly do you mean when you say it doesn't work sometimes? Is the noLocation function being called? If so, you can add an error parameter to noLocation() and then error.code and error.message may help you in debugging. It might also help us to know what browser you're using and if you see the same problem in different browsers.Foundling
I mean that sometimes it gives me the lat-lon, and sometimes it doesn't. when it doesn't work, it doesn't even throw the "could not find location" message so the noLocation bit isn't firing either.Viv
related question https://mcmap.net/q/111490/-function-fail-never-called-if-user-declines-to-share-geolocation-in-firefox/194609Dionne
You're not setting any options. Try geolocator.js - github.com/onury/geolocatorVolley
M
391

I have a partial answer, but alas not a complete one.

First of all, realise that the default timeout for getCurrentPosition is infinite(!). That means that your error handler will never be called if getCurrentPosition hangs somewhere on the back end.

To ensure that you get a timeout, add the optional third parameter to your call to getCurrentPosition, for example, if you want the user to wait no more than 10 seconds before giving them a clue what is happening, use:

navigator.geolocation.getCurrentPosition(successCallback,errorCallback,{timeout:10000});

Secondly, I have experienced quite different reliability in different contexts. Here at home, I get a callback within a second or two, although the accuracy is poor.

At work however, I experience quite bizarre variations in behavior: Geolocation works on some computers all the time (IE excepted, of course), others only work in chrome and safari but not firefox (gecko issue?), others work once, then subsequently fail - and the pattern changes from hour to hour, from day to day. Sometimes you have a 'lucky' computer, sometimes not. Perhaps slaughtering goats at full moon would help?

I have not been able to fathom this, but I suspect that the back end infrastructure is more uneven than advertised in the various gung-ho books and websites that are pushing this feature. I really wish that they would be a bit more straight about how flakey this feature is, and how important that timeout setting is, if you want your error handler to work properly.

I have been trying to teach this stuff to students today, and had the embarassing situation where my own computer (on the projector and several large screens) was failing silently, whereas about 80% of the students were getting a result almost instantly (using the exact same wireless network). It's very difficult to resolve these issues when my students are also making typos and other gaffes, and when my own PC is also failing.

Muskmelon answered 7/10, 2010 at 19:26 Comment(11)
Good detailed info, thanks! I'm seeing the same problems, but only on Firefox 3.6.13. Chrome seems to be quite reliable.Bole
Same here, and the maximumAge parameter seems to be unreliable too. Thanks for the post.Chandos
Nice one, I had the same issue (on a Samsung Galaxy Tab, 10.1, running Android 4.0.3), once I used the timeout param above, I was able to handle the issue.Geotropism
On Win8: Google Chrome v30 - works for the first time and then always fails. IE10/11 works every time. Firefox v24 always fails.Valediction
I find that if I close my browser down and relaunch, my position is returned rather quickly. If I then refresh the browser and try again, it fails. I try again later and it works! Thanks for the timeout suggestion - this will help tremendously. Very unreliable feature. It's shame because it's a very important one for various projects of mine.Odyl
Another tip: if like me you don't need 100% precise location, just an area, you can set enableHighAccuracy:false and the whole process can be a lot quicker. Setting it to false has hardly affected anything - it's still pretty accurate. I'm not showing a marker on the map when the position is found, I just want the map's view to be in the right area to start with.Odyl
It's important to understand what the timeout option in getCurrentPosition() is actually timing. It does not time the user to allow or deny the geolocation request, but how long the network is allowed to take to return a location once permission is granted. If the user does not answer the geolocation request, the error handler will never be called. Thus, you need a second timeout like in @xiaohouzi79 answer.Spermatium
In case of having an hybrid app (cordova based with nested WebView instead of browser) going to Location Services and enabling ALL options (GPS and Wi-fi) will fix odd issues, i just had this using Cordova 3.X and KitKat all working just fineEcstasy
slaughtering goats at full moon would help? LOLNevile
Thanks buddy! Great info and great explanation! Helped me too.Angora
Just my observation, the API doesn't work on incognito tabInfinitude
B
73

This is the hacky way that I am getting around this, at least it works in all current browsers (on Windows, I don't own a Mac):

if (navigator.geolocation) {
    var location_timeout = setTimeout("geolocFail()", 10000);

    navigator.geolocation.getCurrentPosition(function(position) {
        clearTimeout(location_timeout);

        var lat = position.coords.latitude;
        var lng = position.coords.longitude;

        geocodeLatLng(lat, lng);
    }, function(error) {
        clearTimeout(location_timeout);
        geolocFail();
    });
} else {
    // Fallback for no geolocation
    geolocFail();
}

This will also work if someone clicks the close or chooses no or chooses the Never Share option on Firefox.

Clunky, but it works.

Bessette answered 1/12, 2011 at 11:17 Comment(6)
+1 But you're missing the geolocFail(); error handler and the getcodeLatLng(); geo coder.Ahoufe
Sweet - the timer works beautifully if someone chooses not to share a location. Some browsers do not play well when users do this. This timer workaround worked great on my Store Locator Plus WP Plugin!Synthetic
@sajith - Not sure if this solution is now outdated with recent FF browsers. It worked at the time I provided the solution because I needed it for a site I was working on. Have you tested?Bessette
sorry,it worked.But i cant find what makes it work.After closing and reopen the FF its working........thanx for your solution....Persia
You should not use function inside string. Evil eval works there unnessesarrily. setTimeout("geolocFail()", 10000);Beaird
This may seem hacky, but it works like a champ! Sad part about this is that you posted this in 2011...it's now 2017 and the same clunky solution is still required even for the latest FireFox.Counterblast
P
50

This works for me every time:

navigator.geolocation.getCurrentPosition(getCoor, errorCoor, {maximumAge:60000, timeout:5000, enableHighAccuracy:true});

Though it isn't very accurate. The funny thing is that on the same device if I run this it puts me off about 100 meters (every time), but if I go to google's maps it finds my location exactly. So although I think the enableHighAccuracy: true helps it to work consistently, it doesn't seem to make it any more accurate...

Pooh answered 10/5, 2012 at 19:2 Comment(5)
This has stopped firefox from denying the request and sending back a timeout object.Czarevitch
The 100 meters away is the cell tower I'm attached to. So it's returning the location of the cell tower, not my phone. Might be more accurate if I was outside for the gps to kick in.Definite
It keeps putting you off a couple of meters because you have the maximumAge paremeter set to 60 seconds. So its putting your location where you were at 60 seconds ago. Set maximumAge to 10 seconds or less (maximumAge: 10000) and try again.Lundberg
I was using this getCurrentPosition within an Angular Resolver that returns an Observable. The Resolver only completed intermittently. Adding these options: {maximumAge:60000, timeout:5000, enableHighAccuracy:true} made it work every time!!!Pharyngitis
I found FireFox, Safari to work well, Chrome right now comes back with a shorter number which is very inaccurate.Colatitude
X
33

This is already an old question, but all answers didn't solve my problem, so let's add the one I finally found. It smells like a hack (and it is one), but works always in my situation. Hope in your situation too.

//Dummy one, which will result in a working next statement.
navigator.geolocation.getCurrentPosition(function () {}, function () {}, {});
//The working next statement.
navigator.geolocation.getCurrentPosition(function (position) {
    //Your code here
}, function (e) {
    //Your error handling here
}, {
    enableHighAccuracy: true
});
Xena answered 10/8, 2015 at 9:59 Comment(2)
That is the hackiest of hacks, and I have no idea how you even thought to try that, but it solves my problem. Thank you!Selwin
I've used this myself in some cases. Second attempt always works better in my experienceProportioned
G
17

Same here people, this works perfect btw in Chrome (stable, dev and canary) just not in FF and Safari. It also works perfect on my iPhone and iPad (Safari!). This might be due to the relative newness of this feature (i.e. it is a bug). I spend almost a week on this now and I just cannot get it to work on those browsers

Here's what I found:

The first time you call getCurrentPosition it works perfect. Any subsequent call never returns, i.e. it does not fire the successCallback or the errorCallback functions. I added a few position options to my call to prove my point:

 navigator.geolocation.getCurrentPosition(successCallback, errorCallback,  {timeout: 10000});

and it times out every time (after the first successful call). I thought I could fix it with maximumAge, but that doesn't seem to be working as it is suppose to work either:

navigator.geolocation.getCurrentPosition(successCallback, errorCallback,  {maximumAge:60000, timeout: 2000});

this should prevent actually calling the getCurrentPosition function if you call it within 60 seconds, but it ignores this (however, this could be due because I actually refresh my page to trigger the second call, not sure if this is persistent accross calls)

btw, even google's examples fail on these browsers which leads me to believe that this are indeed browser bugs, try it, load it twice in Safari and it won't work the second time.

If anybody finds a solution for this, PLEASE let me know :-)

Cheers.

Gonophore answered 11/9, 2010 at 6:26 Comment(1)
I have the exact problem as yours, it works for the first call but never the next ones, if anyone find a solution i would be very intersted... @xiaohouzi79 your solution ends every time(except for the frist one) in geolocFail()Dirndl
U
15

You don't get an error message because it has no timeout by default (At least i think). I have had the same problem with firefox only for me firefox always gives an timeout. You can set a timeout yourself like this.

My function works great in chrome but i get a timeout everytime in firefox.

    navigator.geolocation.getCurrentPosition(
        function(position) {
            //do succes handling
        },
        function errorCallback(error) {
            //do error handling
        },
        {
            timeout:5000
        }
    );

I recommend to watch your errors carefully. Be expected for everything. Have a backup plan for everything. I use some default values or values from my database myself in case both google geolocations and navigator geolocations fails.

Underlay answered 10/12, 2010 at 1:33 Comment(2)
just an FYI, maximumAge refers to the age of the location data in cache, setting it to infinity guarantees you'll get a cached version. Setting it to 0 forces the device to retrieve the position.Tear
downvoted because maximumAge: Infinity will screw you up as pointed out above it means force use cached value.Spongioblast
K
11

I'll post this here in case it's useful to anyone…

On iOS Safari, calls to navigator.geolocation.getCurrentPosition would timeout if I had an active navigator.geolocation.watchPosition function running.

Starting and stopping the watchPosition properly using clearWatch() as described here, worked: https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition

Kneepad answered 16/8, 2017 at 16:13 Comment(1)
Thank you so much. This was the solution for me.Gleaning
D
9

I'm still getting spotty results in 2017, and I have a theory: the API documentation says that the call is now only available "in a secure context", i.e. over HTTPS. I'm having trouble getting a result in my development environment (http on localhost) and I believe this is why.

Deadradeadweight answered 13/6, 2017 at 14:2 Comment(2)
Hmm interesting. Even in 2020 it's still flaky with HTTPS on localhost!Thorsten
Since 2021 localhost is seen as secure context even with http, see hereTrachytic
D
7

here is my solution thanks to a closure :

  function geoloc(success, fail){
    var is_echo = false;
    if(navigator && navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        function(pos) {
          if (is_echo){ return; }
          is_echo = true;
          success(pos.coords.latitude,pos.coords.longitude);
        }, 
        function() {
          if (is_echo){ return; }
          is_echo = true;
          fail();
        }
      );
    } else {
      fail();
    }
  }

  function success(lat, lng){
    alert(lat + " , " + lng);
  }
  function fail(){
    alert("failed");
  }

  geoloc(success, fail);
Donaldson answered 10/2, 2012 at 11:49 Comment(2)
This worked for me in react-native navigator && navigator.geolocationSelfreproach
This sould have more upvotes.. It worked out of the box in Firefox!!! Thanks buddy!!! :)Retrochoir
W
6

As of mid 2020, none of the answers here provides any explanation, just hacking or guessing.

As @Coderer points out before me, secure context (https) is required today, so on more and more devices geolocation doesn't work at all with plain http:

Secure context This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

The third parameter of getCurrentPosition() (and watchPosition() which is more suitable here) is PositionOptions object consisting of these properties:

  • enableHighAccurancy (default false): if set to true, response is slower and more accurate. If you got timeout errors, keep this to false. If the accurancy is low, set it to true. In my tests the accurancy varies and on some devices it has no effect. On other devices setting true may cause surprisingly quick battery depletion.
  • timeout (default infinity): milliseconds before the API gives up and calls the error handler (the second parameter). Today most mobile devices with geolocation enabled and permission granted for the browser/page get the value with reasonable accurancy within a second. When the geolocation service is not available, alternative method like geo IP may be used, the delay can be many seconds and the precision usually ranges from questionable to useless.
  • maximumAge (default 0): milliseconds when cached value is valid, the device may decide to use valid cached data instead of sensor measure. I usually set this to non-zero values with slowly moving devices (like walking with mobile phone). On static devices, Infinity can be set to avoid consequent reading errors.

As @YoLoCo points out before me, getCurrentPosition() and watchPosition() interferes and I confirm his results in 2020. Generally, use watchPosition instead of getCurrentPosition periodical calls.

Wollongong answered 4/7, 2020 at 6:30 Comment(2)
Never heard of the possibility to set "Infinity". Solve my problem with the local environment where a second call to geolocation.getcurrentPosition was not resolving positivly and therefore blocked a dependent call to another function. – Let's see what happens with the live version...Tedra
setting enableHighAccurancy to false speed things up! thanksOberheim
F
5

So I was running into the same thing. I tried the timeout solution which worked but not reliably. I found that if you just call it twice the location is refreshed properly

function getLocation(callback)
{   
    if(navigator.geolocation)
    {
        navigator.geolocation.getCurrentPosition(function(position)
        {
            navigator.geolocation.getCurrentPosition(callback, function(){},{maximumAge:0, timeout:10000});
        },function(){}, {maximumAge:0, timeout:10000});
    }
    return true;
}

this of course is a little slower but I have not had it give me the wrong position once. I have had it hit the timeout a few times and not return anything but other then that it works great. I know this is still a little hacky and I am looking forward to someone finding the real solution.

Or if you want to make sure it is going to keep trying until you want to give up you could try something like this.

//example
$(document).ready(function(){
    getLocation(function(position){
        //do something cool with position
        console.log(position);
    });
});


var GPSTimeout = 10; //init global var NOTE: I noticed that 10 gives me the quickest result but play around with this number to your own liking


//function to be called where you want the location with the callback(position)
function getLocation(callback)
{   
    if(navigator.geolocation)
    {
        var clickedTime = (new Date()).getTime(); //get the current time
        GPSTimeout = 10; //reset the timeout just in case you call it more then once
        ensurePosition(callback, clickedTime); //call recursive function to get position
    }
    return true;
}

//recursive position function
function ensurePosition(callback, timestamp)
{
    if(GPSTimeout < 6000)//set at what point you want to just give up
    {
        //call the geolocation function
        navigator.geolocation.getCurrentPosition(
            function(position) //on success
        {
                //if the timestamp that is returned minus the time that was set when called is greater then 0 the position is up to date
            if(position.timestamp - timestamp >= 0)
                {
                    GPSTimeout = 10; //reset timeout just in case
                    callback(position); //call the callback function you created
                }
                else //the gps that was returned is not current and needs to be refreshed
                {
                    GPSTimeout += GPSTimeout; //increase the timeout by itself n*2
                    ensurePosition(callback, timestamp); //call itself to refresh
                }
            },
            function() //error: gps failed so we will try again
            {
                GPSTimeout += GPSTimeout; //increase the timeout by itself n*2
                ensurePosition(callback, timestamp);//call itself to try again
            },
            {maximumAge:0, timeout:GPSTimeout}
        )
    }       
}

I probably have some typeos and some spelling errors in here but I hope you get the idea. Let me know if anyone has questions or if someone finds something better.

Faustena answered 29/1, 2013 at 20:7 Comment(0)
E
4

For anyone working on an iPhone app...

If your code is running in a UIWebView on iOS 9+, then you must set NSLocationWhenInUseUsageDescription within your app's plist.

If you don't set it then getCurrentPosition will never call back and the user will never be prompted.

Eleen answered 28/10, 2015 at 18:48 Comment(0)
A
3

The second parameter passed to Geolocation.getCurrentPosition() is the function you want to handle any geolocation errors. The error handler function itself receives a PositionError object with details about why the geolocation attempt failed. I recommend outputting the error to the console if you have any issues:

var positionOptions = { timeout: 10000 };
navigator.geolocation.getCurrentPosition(updateLocation, errorHandler, positionOptions);
function updateLocation(position) {
  // The geolocation succeeded, and the position is available
}
function errorHandler(positionError) {
  if (window.console) {
    console.log(positionError);
  }
}

Doing this in my code revealed the message "Network location provider at 'https://www.googleapis.com/' : Returned error code 400". Turns out Google Chrome uses the Google APIs to get a location on devices that don't have GPS built in (for example, most desktop computers). Google returns an approximate latitude/longitude based on the user's IP address. However, in developer builds of Chrome (such as Chromium on Ubuntu) there is no API access key included in the browser build. This causes the API request to fail silently. See Chromium Issue 179686: Geolocation giving 403 error for details.

Aedes answered 13/10, 2016 at 18:20 Comment(0)
S
2

I have been having similar issues, and have been looking into the possibility that browsers have limits on how often getCurrentPosition can be called. It seems I can often get a location, but if i refresh the page right away it will time out. If I wait for a bit, I can usually get a location again. This usually happens with FF. In Chrome and Safari, I have not yet noticed getCurrentPosition timing out. Just a thought...

Although I cannot find any documentation to support this, it was a conclusion I came to after much testing. Perhaps someone else has has some info about that?

Stahl answered 18/11, 2011 at 20:17 Comment(2)
That's a good point. My timeouts/fails seem to happen mostly when I'm testing and am repeatedly querying geolocation data. I'm anxious to know if this is the result of a bug or, as you suggest, possibly by design.Marchpast
I've not seen any case where the browser limits the amount of calls to the location services. How often are you querying?Proportioned
S
2

I finally found a working version for firefox, chrome & default navigator in android (4.2 tested only):

function getGeoLocation() {
        var options = null;
        if (navigator.geolocation) {
            if (browserChrome) //set this var looking for Chrome un user-agent header
                options={enableHighAccuracy: false, maximumAge: 15000, timeout: 30000};
            else
                options={maximumAge:Infinity, timeout:0};
            navigator.geolocation.getCurrentPosition(getGeoLocationCallback,
                    getGeoLocationErrorCallback,
                   options);
        }
    }
Sycophancy answered 9/7, 2013 at 5:29 Comment(0)
R
2

I have this problem in Mozilla. All time: Error: Unknown error acquiring position.

Now i'm using 47 Mozilla. I have tried everything, but all time this problem. BUT then i open about:config in my addsress bar, go geo.wifi.ui and changed it value to "https://location.services.mozilla.com/v1/geolocate?key=test". works!

If u have Position acquisition timed out error, try to increase timeout value:

var options = {
  enableHighAccuracy: true,
  timeout: 5000,
  maximumAge: 0       
};
navigator.geolocation.getCurrentPosition(success, error, options);
Reptant answered 13/7, 2016 at 14:53 Comment(0)
T
2

@brennanyoung's answer is great, but if you're wondering what to do in the failure case you could use an IP geolocation API such as https://ipinfo.io (which is my service). Here's an example:

function do_something(coords) {
    // Do something with the coords here
    // eg. show the user on a map, or customize
    // the site contents somehow
}

navigator.geolocation.getCurrentPosition(function(position) { 
    do_something(position.coords);
    },
    function(failure) {
        $.getJSON('https://ipinfo.io/geo', function(response) { 
        var loc = response.loc.split(',');
        var coords = {
            latitude: loc[0],
            longitude: loc[1]
        };
        do_something(coords);
        });  
    };
});

See https://ipinfo.io/developers/replacing-getcurrentposition for more details.

Tucson answered 23/9, 2016 at 17:43 Comment(5)
Here is the corrected link for this: ipinfo.io/developers/replacing-getcurrentpositionRoesler
Terrible. The accuracy is like a 5-7 miles away from the real position when in US and Canada and 100 miles away when somewhere in Russia.Orion
For a lot of applications that's fine - and a lot better than have no idea what the location is.Tucson
this not works anywhere. Every requests getting longitude and latitude as wrongLm
What do you mean by wrong? Do you have some examples?Tucson
H
2

I found, that this way doesn't work

navigator.geolocation.getCurrentPosition(function() {...}, function(err) {...}, {});

But

this way works perfect

function storeCoordinates(position) {
    console.log(position.coords.latitude, position.coords.longitude);
}    

function errorHandler() {...}

navigator.geolocation.getCurrentPosition(storeCoordinates, errorHandler, { enableHighAccuracy: true, timeout: 20000, maximumAge: 0 });
Hally answered 28/3, 2018 at 23:42 Comment(5)
What's difference between both?Kynewulf
Anonymous function vs named oneHally
really big differences. thank you, this not working eitherLm
@Lm anytime you can post a workable solution here. We will study it.Hally
there is no clear difference outlined. First one has anonymous functions for callbacks while the second named functions for callbacks and non-default parametersDebera
C
1

In our case it always works the first time but rerunning the function more than 3-4 times, it fails.

Simple workaround: Store it's value in LocalStorage.

Before:

navigator.geolocation.getCurrentPosition((position) => {
  let val = results[0].address_components[2].long_name;
  doSthWithVal(val);      
}, (error) => { });

After:

if(localStorage.getItem('getCurrentPosition') !== null) {
  doSthWithVal(localStorage.getItem('getCurrentPosition'));
}
else {
  navigator.geolocation.getCurrentPosition((position) => {
      let val = results[0].address_components[2].long_name;
      localStorage.setItem('getCurrentPosition',val);
      doSthWithVal(val);      
  }, (error) => { });
}
Chronopher answered 19/6, 2019 at 21:12 Comment(0)
H
0

I noticed this problem recently myself, and I'm not sure how it comes about but it would appear sometimes firefox gets stuck on something loaded in cache. After clearing cache and restarting firefox it appears to function again.

Hypostasis answered 22/4, 2013 at 16:48 Comment(0)
L
0

Thanks to everyone for their input, this helped me.

In addition to having to use watchPosition() instead of getCurrentPosition(), I also found that I needed to move the call from within document.ready() to the head.

Linwoodlinz answered 14/8, 2015 at 18:34 Comment(0)
V
0

This happened to me when using Firefox's responsive design mode. There has been a bug report filed. For now, just don't use responsive design mode while using the Geolocation API.

Voigt answered 29/5, 2020 at 16:54 Comment(0)
P
0

May be it helps some one, On Android i had same issue but i figured it out by using setTimeout inside document.ready so it worked for me secondly you have to increase the timeout just incase if user allow his location after few seconds, so i kept it to 60000 mili seconds (1 minute) allowing my success function to call if user click on allow button within 1 minute.

Panathenaea answered 12/6, 2020 at 3:44 Comment(0)
G
-2

This library adds a desiredAccuracy and maxWait option to geolocation calls, which means it will keep trying to get a position until the accuracy is within a specified range.

Guzzle answered 13/11, 2014 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.