HTML5 Geolocation API – how accurate is it, really?

If you are a developer building applications that require location information then you need to know what is really possible with the HTML5 Geolocation API and not a bunch of hype. The blog post attempts to give you some insight into how it works with desktop and mobile browsers as well as having a greater appreciation for what is and what isn’t possible. I’m going to show you that 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.

[Editors note: as of June 29th, 2013 Part 2 of this post is now available]

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.

As an example to show you what type of information is sent to a Location Service, I did some basic testing with Firefox 11. Firefox uses Google’s Location Service. On a related note, as far as I can tell with Firefox 11 it isn’t passing cookies any more where in Firefox 3.6 they use to pass a user ID token.

Firefox 11 browser sends queries to https://maps.googleapis.com/maps/api/browserlocation/json? The example results have been obfuscated, but by looking at it you should get the idea of what content is being sent:

GET /maps/api/browserlocation/json?browser=firefox&sensor=true&wifi=mac:01-24-7c-bc-51-46%7Cssid:3x2x%7Css:-37&wifi=mac:09-86-3b-31-97-b2%7Cssid:belkin.7b2%7Css:-47&wifi=mac:28-cf-da-ba-be-13%7Cssid:HERESIARCH%20NETWORK%7Css:-49&wifi=mac:2b-cf-da-ba-be-10%7Cssid: ARCH%20GUESTS%7Css:-52&wifi=mac:08-56-3b-2b-e1-a8%7Cssid:belkin.1a8%7Css:-59&wifi=mac:02-1e-64-fd-df-67%7Cssid:Brown%20Cow%7Css:-59&wifi=mac:2a-cf-df-ba-be-10%7Cssid: ARCH%20GUESTS%7Css:-59 HTTP/1.1

Which location service do browsers use?

Not all Geolocation services are the same, and they certainly don’t all use the same algorithms and exact same databases. Because of this the results typically vary across browsers that use different Geolocation services.

Here’s my best attempt to document which Geolocation service each of the major browsers are using. I haven’t done any definitive testing however I do know from experience that different browsers and even different laptops for smartphones will return different locations when tested from the exact same location. Some location services are better in some cities and others are better in other cities. I haven’t come across a definitive list, most likely because the information is constantly being updated. I’ve included a link to a demo application at the bottom of this blog where I encourage you to also test the API against different browsers.

  • Chrome uses Google Location Services.
  • Firefox on Windows uses Google Location Services.
  • Firefox on Linux uses GPSD – http://catb.org/gpsd/. I’m not sure if this includes Android. I haven’t had a chance to test it yet.
  • Internet Explorer 9+ uses the Microsoft Location Service.
  • Safari on iOS uses Apple Location Services for iPhone OS 3.2+.
  • I’m not sure what Safari on Windows uses. With all the public distrust between Apple and Google, I wouldn’t be surprised if Safari on Windows also uses Apple’s Location Service, but I haven’t found any documentation to verify this and I haven’t tested it.
  • Opera uses Google Location Services. On a related note, I’ve also noticed that mobile Opera on Android accesses the GPS. This is something to consider from a battery usage standpoint.

Not all browsers support HTML5. It’s important to note that not all browsers support the HTML5 Geolocation API, for example Internet Explorer 8. The HTML5 Geolocation API is built into the browser and is accessible using JavaScript methods that access the navigator object. In order to work it requires HTML5 support in the browser. You can research whether or not a particular browser supports Geolocation by going here: http://mobilehtml5.org/ or http://caniuse.com.

Additionally, if a user has disabled JavaScript for some reason, then your Geolocation app won’t work in their browser. JavaScript code is required to access the API.

HTML5 Geolocation requires an internet connection. If you lose your internet connection then you won’t be able to access the Location Service. With no internet connection most browsers will not return a location. Sometimes you can access a cached location that is stored in the browser by the API. But, that cached location is the last valid location that was calculated by the API.

Is Wifi turned on or off? If Wifi is turned off on your phone, desktop machine, laptop or tablet , the Geolocation API service will try to find your location by other methods which include your public IP address, Cell tower ID triangulation or GPS. Public IP addresses databases usually return a location for your internet providers Point of Presence or PoP. Furthermore, some internet provides offer rotating IP addresses. So you get to use one IP address for a particular time period such as 48 hours and then you get a different one. So a Public IP address is usually only good enough to locate you to a particular City, or a general area of the City, or a Country depending on where you are in the world.

As for Cell Tower IDs it depends on what type of information your particular phone and Telco Carrier provides to the API. Some smartphones only return information on the current tower that the phone is pinging, which obviously makes triangulation very difficult and decreases accuracy to within a radius around that tower.

I’ve noticed that the native Android browser is significantly less accurate without Wifi. Without it I typically see accuracy numbers in the 1000+ meters range. As soon as I turn Wifi back on and I’m in a neighborhood or downtown area, the accuracy drops to less than 75 meters almost instantly.

Are they in a rural or urban location? Granted the vast majority of users will be in urban locations. However if you have requirements for users traveling outside of urban areas then this section applies to you. Geolocation in rural areas is significantly less reliable. If Wifi is turned on but the user is not near any Wifi access points, then the Geolocation service will also attempt to fallback to the other methods mentioned above.  Triangulation can be much more difficult in rural areas where towers are spread further apart, and for browsers that don’t use GPS the accuracy will suffer significantly.

Are you moving or stationary? Being stationary in an urban area offers far better accuracy with the Geolocation API than when you are moving. On my native Android phones it’s rare to get an accurate reading while driving around town. Occasionally a sporadic result would be returned when you stop at a light. To date, I have never gotten a valid reading while driving on a highway at speeds over 50 mph.

Is a VPN turned on? If a VPN is turned on, then the location will resolve to the VPN’s public IP address. For example, a user in Denver is logged into the company VPN which host is hosted at their headquarters office in a suburb of Dallas, Texas. The HTML5 Geolocation API will resolve the location to the headquarters public IP address in Dallas and not the user’s actual location. Quite a few corporate users have VPNs for security reasons.

Custom Geolocation as a fallback? Depending on your requirements you may want to implement your own IP Geolocation using a company such as IP2Location. Or use a third-party Geolocation service, such as Skyhook, as a fallback. Remember IP Geolocation only returns locations to a City or an area within a City. So, if you need more accuracy than that for your application, then don’t bother with this approach.

The downside to custom IP Geolocation is that this requires writing a server-side service to grab the browsers IP address. All server-side languages such as PHP, C#.NET, Java and JSP support these capabilities. You also have to subscribe to another service that lets you query their database by IP address and get a return value of an approximate location. There is no current way to get this information from the browser, on the client-side, using JavaScript.

HTML5 Geolocation doesn’t meet my requirements, what do I do? If you have critical requirements for gathering more precise location information than the HTML5 Geolocation API is capable of delivering then I’d recommend building your application using a native API such as Android or iOS.

How can I test this? You can test HTML5 Geolocation in different browsers using a test application that I built. I recommend trying it on different browsers and comparing the results yourself:

http://andygup.net/samples/html5geo/

References

Mozilla FAQ

Mozilla Developer Network

Google Location Service

W3C Geolocation API in IE 9

Safari Developer Library

Opera Geolocation

IP Geolocation

W3C – Privacy of Geolocation Implementations

Apple Q&A on Location Data

Common pitfalls with JavaScript scope

I’m a firm believer that JavaScript’s flexibility is great for small projects with a single developer. But, its flexibility can become a seriously liability in medium to large projects if not managed properly. The ‘scope’ of a variable can cause some of the largest headaches for developers. And, in big projects tracking down an improperly scoped variable will take time, and it will try your patience.

In most cases, variables in JavaScript have two scopes: global and private. Scope is the context in which a variable is used. A global variable is defined outside of any function() in a JavaScript text block, and it can be accessed from inside any function(). Any change to a global variable will be reflected where ever else that variable is used. A private variable is defined only inside a function() and private variables are not accessible by other function()’s by definition. So a change to a private variable only changes it’s own value and doesn’t affect any other variable outside the scope of the function(). If you are new to scope, you may want to re-read this paragraph twice.

If you’ve been using JavaScript for any amount of time you’ll discover that simply misplacing a “var” statement in front of a variable causes it become global in scope. And, if you happen to already have a global variable somewhere else by the same name then these values can overwrite each other. If you are working on a project with thousands of lines of code and multiple .js libraries then your problems can get larger. I’ve accidentally deleted a “var” keyword in several cases and then spent a considerable head banging tracking it down.

To demonstrate these pitfalls, I’d rather show you in code what the problems are. Hopefully by reading this, and understanding a bit more about scope and by using best practices, you’ll avoid the common pitfalls as much as possible.

Scenario 1– properly defined private variables. This scenario demonstrates best practices for defining local variables within a function(). You can have privately scoped variables with the same name as global variables because of JavaScript obeying adherence to scope. Click here to try out this scenario.

  //This sets a global variable scope
  var color = "blue";

  function init() {

	var me = new Person("Andy");
	alert(" Private scoped name: " + me.name +
	   "\r\n Private scoped color: " + me.favoriteColor +
	   ", \r\n Global scoped color: " + color
	);

  }

  function Person(myname)
  {
	  //This creates a privately scoped variable
	  //Does not affect or change the globally scoped
	  //variable of same name
	  var color = "red";

	  //myname exists within the private scope of the function
	  //color is privately scoped
	  this.name = myname;
	  this.favoriteColor = color;
  }

Scenario 2 – improper use of a global variable. This scenario demonstrates forgetting to set “var” on the variable color. The value of the global variable named color is changed. If you use this pattern for manipulating global variables you are asking for trouble as your project grows larger. Click here to try out this scenario.

  //This sets a global variable scope
  var color = "blue";

  function init() {

	var me = new Person("Andy");
	alert(" Private scoped name: " + me.name +
	   "\r\n Private scoped color: " + me.favoriteColor +
	   ", \r\n Global scoped color: " + color
	);

  }

  function Person(myname)
  {
	  //This changes the globally scoped
	  //variable of same name
	  color = "red";

	  //myname exists within the private scope of the function
	  //color exists within the global scope of the application
	  this.name = myname;
	  this.favoriteColor = color;
  }

Scenario 3 – this scenario shows the best practice for passing in a global variable to a function(). By passing the global variable into someColor you protect the scope of it within the function(). Click here to try this scenario.

  //This sets a global variable scope
  var color = "blue";

  function init() {

	var me = new Person("Andy", color);
	alert(" Private scoped name: " + me.name +
	   "\r\n Private scoped color: " + me.favoriteColor +
	   ", \r\n Global scoped color: " + color
	);

  }

  function Person(myname, someColor)
  {
	  //myname exists within the private scope of the function
	  //someColor is a private scope, but it inherits the value
	  //of the variable passed to it.
	  this.name = myname;
	  this.favoriteColor = someColor;
  }

References:

Scope in JavaScript by Mike West
Variable Scope for New Programmers by Jonathan Snook

The Largest Conference For Mapping and Geospatial Developers – Esri DevSummit 2012

I’ll be presenting at the Esri DevSummit next week so if you are attending please swing by my sessions and say “hi”. If you aren’t familiar with Esri or the conference, about 1400 developers and other technical experts converge on Palm Springs, California every Spring to learn all things technical about building commercial and enterprise geographic information systems. There will be everything from introductory Dojo workshops to deep dives into the heart of our APIs.

If you’re around here’s my schedule. I’d be very interested to hear about what you are working on:

Monday,  March 26

Getting Started with the ArcGIS Web APIs – 8:30am – 11:45am, Pasadena Room. I’ll be presenting the portion related to our ArcGIS API for JavaScript.

Gettings Started with Smartphone and Tablet ArcGIS Runtime SDKs – 1:15pm – 4:45pm, Pasadena Room. In this session, I’ll be presenting on our ArcGIS Runtime SDK for Android.

Wednesday, March 28

Flex the World – 10:30am, Demo Theater 2. I’ll be presenting with my esteemed colleague Sajit Thomas on Apache Flex.

7 required improvements for the Web, HTML and JavaScript

Here’s my 2012 web developer wish list for improvements that I’d like to see happen in the web developer world. If HTML and JavaScript want to be considered enterprise ready for commercial-grade deployments then here’s some things that are needed today.

For clarity, I consider a commercial software deployment to be one that contains over one thousand lines of code, at least two custom .js libraries and involves at least two developers and some sort of code versioning system.

  1. Refactoring. Not having this capability continues to be a huge productivity issue for large projects. Try refactoring across six JavaScript libraries and 1200 lines of code using Notepad++.
  2. Even stronger scope enforcement in JavaScript classes. One wrong misspelling and you can spend fun filled hours (or days) tracking down a private variable that turned itself into a global variable.
  3. Built-in support for code comments. Visual Studio does a fine job, for example. But, it’s still kind of a hack to make it work. I’d like the built-in ability to create comments for methods and classes directly and then be able to access those comments via intellisense throughout any file in the project. Again, this is all about productivity by having this information accessible at your fingertips.
  4. Better built-in JavaScript checking for IDEs. I’d like to see built-in JSLint-like capabilities that have been updated to the latest HTML, JavaScript and CSS3 versions, and not some third party plug-in that’s optional.
  5. Best practice whitepapers. These would be whitepapers written by the browser vendors that provide guidelines on the correct patterns to use when building apps against their browsers. Seriously, it’s been roughly 21 years since we started using browsers and there’s no guidance at all from the powers that be.  Honestly, I’m stunned that these don’t exist. That would be similar to Microsoft publishing .NET and then not providing any conceptual help documentation.
  6. Official tools for browser certification and testing. The folks that build the browsers don’t give us a way to verify if we are building our apps in the best way possible. If these items existed, then quality could get a lot better, and we’d all learn a lot too.
  7. Slower browser release cycles. A slower release cycle for browsers and more improved security and stability. I already blogged about this here.

HTML 5 and Web Maps Seminar

@derekswingley and I are presenting several one hour Live Training Seminars on HTML5 and ArcGIS for developers on Thursday, February 23, 2012. ArcGIS is the flagship mapping and geo-spatial product line for the company I work for: Esri. Now, even if you aren’t currently using anything geo I still encourage you to listen in for an hour and hear what we have to say about HTML5 from a web app development perspective.

We’ve aimed the content at both new developers and experience developers that haven’t had a chance to play with HTML5 yet. Our goal is to help you understand what HTML5 really is and give some concrete uses cases and tips on how to effectively use it. So, sign on up, hopefully gain some new insight and ask some questions!

Click here to find out more details.

Simple Native JavaScript Classes – So simple a caveman could do it.

Among the many things I severely dislike about JavaScript is working with applications that have oodles of global variables, multiple .js libraries and dozens of loosely organized, individual functions. This is a very common pattern (or perhaps an anti-pattern). But it’s a terrible way to code for medium to large projects, especially where you have to share your code. Here’s a highly simplified example:


var someNumber = 2; //Global variable

function add(number){
    return someNumber + number;
};
alert(add(4)); //displays "6"

It’s unfortunate that this pattern is reinforced in authoritative books, blogs and articles. It’s completely pervasive in the majority of examples you see on the web. The downside is modifying, testing and troubleshooting this pattern can be an absolute nightmare. I compare it to building a fragile, multi-level house of cards: one wrong bump and it all falls down.

There is a better way!

So, I offer an easy-to-implement solution: where possible place your functions and properties in Class-like objects and all will be so much better. It’s not quite what you get with strongly-typed object oriented languages like C# or Java, but it works. Besides, if you use this pattern in your project then cats and dogs will live peacefully side-by-side and the universe will be in balance. The best news: this works perfectly fine with plain old JavaScript (POJO). And, if you are using something like jQuery use can use some version of Classes with those too, and I highly recommend it.

Here’s the fundamental pattern of a JavaScript Class:

function Add(){};
var someMath = new Add();

That’s very easy…right?? The advantages are many and include the following:

  • You get a powerful framework for logically grouping functionality. This lends to scalability and ultimately stability in your projects.
  • You can easily extend this pattern using prototypal inheritance.
  • You can take advantage of encapsulation.
  • You can implement inheritance and polymorphism.
Now let’s put this pattern to use. I’m providing two examples here. There are several other syntactical ways of doing this, but for brevity I’m sticking with two. The first example uses a very basic Object to implement namespace-like behavior. I say namespace-like because it’s not a true namespace like in C# or Java. The second example uses the built-in windows Object as a way of passing the namespace information. Click here to download a sample app that demonstrates these concepts.

POJO Class Pattern using Object Namespaces

Here’s an expanded example of the pattern with two levels of namespace separation using a standard Object :

if (!com) var com = {};    //1st level namespace
if (!com.ag) com.ag = {};  //2nd level namespace
if (!com.ag.Add) {
    com.ag.Add = function (value) {
        /// <summary>Demonstrates the plain old JavaScript pattern for classes.</summary>
        /// <param name="value" type="Number">Any number.</param>

        this.getValue = function () {
            /// <summary>Returns the property passed to the constructor.</summary>
            /// <returns type="Number">A number that was passed to the constructor.</returns>
            return value;
        },

        this.add = function (number) {
            /// <summary>This method adds value property + number</summary>
            /// <param name="number" type="Number">The number we want to add.</param>
            /// <returns type="Number">The number passed to the contructor plus this number</returns>
            return value + number;
        }

        //For Visual Studio intellisense cues
        com.__namespace = true;
        com.ag.__namespace = true;
        com.ag.Add.__class = true;
    }
}

And, here’s how to use this class:

var test = new com.ag.Add(2);
alert(test.add(4)); //displays "6"

POJO  Class Pattern using window[] Namespaces

Here is a slightly different version of the pattern that uses the window object, the results are the same:

if (!window["NS"]) window["NS"] = {};

window["NS"].Add = function (value) {
    /// <summary>This class uses addition</summary>
    /// <param name="value" type="Number">The number we pass to the contructor.</param>

    this.getValue = function () {
        /// <summary>Returns the private property called value.</summary>
        /// <returns type="Number">The number passed to the contructor.</returns>
        return value;
    },

            this.add = function (number) {
                /// <summary>This method adds value + number</summary>
                /// <param name="number" type="Number">The value we want to add.</param>
                /// <returns type="Number">The number passed to the contructor plus this number</returns>
                return value + number;
            }

    //For Visual Studio intellisense cues
    window["NS"].__namespace = true;
    window["NS"].Add.__class = true;
}

Here’s an example of how to use this class:

var test = new NS.Add(2);
alert(test.add(4)); //displays "6"

You are probably wondering about the funky xml comments. That’s for Visual Studio 2010’s built-in intellisense. I think but I’m not 100% certain that these work with Visual Studio Express as well. If you know for sure then please drop a comment. Notepad++ and other tools are okay for small projects but you can thank me later when you use this Class pattern along with built-in intellisense for any project that involves more than a dozen or so functions. And that’s not all – you can also see intellisense across different .js libraries. It’s all about productivity and ease-of-debugging. And, everyone will thank you when they have to re-use your code.

I’ve also attached a screenshot below to show you what the Visual Studio intellisense looks like. Also note in this example, the physical file, Add.js, in in the directory /scripts/com/ag/Add.js and I’m writing code in index.html which is at the root directory. How cool is that?!

 References

Sample application that demonstrates the Class concepts

Douglas Crockford’s [awesome] JavaScript Blog

Visual Studio JavaScript Intellisense Revisited

Creating Advanced [JavaScript] Web Applications with Object Oriented Techniques

Object Oriented Programming in JavaScript

Write Object Oriented JavaScript Part 1

The Format for JavaScript Doc Comments (Visual Studio)