Monday, January 3, 2011

HTML5 Geolocation API: Your Browser Knows Where You Are

One of the pieces of functionality commonly discussed when distinguishing HTML5 from previous versions of HTML is the standardization of geolocation via the Geolocation API. Although some browsers supported geolocation functionality prior to HTML5, it is the standardized API that brings new value. This is true of many aspects of HTML5 where HTML5 standardizes across compliant browsers what formerly required browser-specific extensions. The geolocation standardization process is not technically part of the HTML5 specification [it is its own World Wide Web Consortium(W3C) specification], but its timing makes it easy to lump in with other HTML5 enhancements. In other words, it is "HTML5" in the larger sense of "next generation HTML" as opposed to strict HTML5 as outlined in the specification. In this blog post, I briefly look at how the standard geolocation approach can be applied and look at browser support for this feature in Internet Explorer 8, Firefox 3.6, Safari 5, and Google Chrome 8. I also indicate how to turn off geolocation support in browsers that support it.

To illustrate the Geolocation API in action, I use the simple HTML code shown next and call it's file simply Geolocation.html:

<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>GeoLocation Demonstrated</title>
    <script language="javascript">
    function verify_geolocation_capability()
    {
       if (navigator.geolocation)
       {
          document.form1.capability.value = "Enabled";
       }
       else
       {
          document.form1.capability.value = "Not Enabled";
       }
    }

    function display_geolocation_properties(position)
    {
       document.form1.capability.value = "W o r k i n g . . .";
       document.form1.latitude.value = position.coords.latitude;
       document.form1.longitude.value = position.coords.longitude;
    }

    function handle_error(error)
    {
       document.form1.capability.value = "ERROR: " + error.code;
    }

    function retrieve_location()
    {
       if (navigator.geolocation)
       {
          document.form1.capability.value = "Starting...";
          navigator.geolocation.getCurrentPosition(display_geolocation_properties, handle_error);
          document.form1.capability.value = "Finished";
       }
       else
       {
          alert("This browser does not support geolocation services.");
       }
    }
  </script>
</head>

<body onload="verify_geolocation_capability()">

  <h1>Latitude and Longitude</h1>

  <form name="form1" id="form1">
    Geolocation Capability: <input type="text" name="capability" value="Unknown">
    <p />
    Latitude:  <input type="text" name="latitude">
    <p />
    Longitude: <input type="text" name="longitude">
    <p />
    <input type="button" name="submit" value="Get Latitude and Longitude" onclick="retrieve_location()">
  </form>

</body>
</html>

Most of the HTML and JavaScript in the example above is to make it easier to see the results. The most important line from a Geolocation API perspective is these lines:

if (navigator.geolocation)
{
   navigator.geolocation.getCurrentPosition(display_geolocation_properties, handle_error);
}

This highlighted code first checks to see if the browser supports the Geolocation API by checking for the existence (support of) naviator.geolocation. If it does exist (is supported), then the code accesses its getCurrentPosition function and passes two function names to it as arguments. The first function, display_geolocation_properties is used for successful responses and the second function name, handle_error, is used to process error responses. As will be shown in later screen snapshots in this post, these methods are invoked asynchronously.

The simple code above typically begins executing in the following order: page load -> verify_geolocation_capability() -> populate "capability" field with text indicating whether geolocation API is enabled or not. Snapshots of the four previously referenced browsers at this point are shown next. Note that the Geolocation API is enabled for Safari 5, Firefox 3.6, and Chrome 8, but is not enabled for Internet Explorer 8.

Safari 5 Supports Geolocation API!

Firefox 3.6 Supports Geolocation API!

Chrome 8 Supports Geolocation API!

Internet Explorer 8 Does NOT Support Geolocation API

The simple HTML application does not do anything further until the user clicks on the button with the text "Get Latitude and Longitude". When that is selected, the code highlighted above relevant to getting position via standardized Geolocation API is executed. In IE's case, the check to make sure that it is supported before trying to access it leads to the Alert popup we expect from looking at the code.


The other three web browsers used in this post do have Geolocation API enabled and so their responses to clicking of the button are more interesting. In fact, their actions at this point are honorable and desirable. It is not surprising that many are uncomfortable with web applications knowing where the user is. Fortunately, the HTML5 Geolocation specification mandates that browsers must seek permission before offering geolocation services to web sites. We see this in action when we click on the button in the three browsers supporting the Geolocation API.

Safari 5 Requests User Permission to Access Location

Firefox 3.6 Requests User Permission to Access Location

Chrome 8 Requests User Permission to Access Location

If the user does not grant this permission, the error handling callback is invoked and provided with an object representing an error. In this simple HTML5 application, the "code" property of that attribute is written to the "capability" field following the "ERROR: " text. This is shown for Safari and Firefox.

Safari 5 Reports Error When User Denies Gelocation Permission

Firefox 3.6 Reports Error When User Denies Gelocation Permission

Let's now be more positive and assume the user does grant the browser to provide geolocation details to the web application. In this simple application, the latitude and longitude are written to the previously empty text fields with the same labels. First, however, because the call is asynchronous, we'll almost always see "Finished" in the "capability" field first and then after some lag of up to a few seconds or more, we'll see "Finished" change to "W o r k i n g . . ." and see the latitude and longitude fields populated. This order occurs because it is almost always the case that the accessing and providing of geolocation data takes longer than it takes for the web browser to execute the next line of JavaScript (setting "capability" field to "Finished"). This phenomenon of asynchronous responses is demonstrated in the following in-order presentation of screen snapshots for Safari and Firefox.





Safari and Firefox both provide more digits in their respective latitudes and longitudes than shown in these edited screen snapshots. When I ran the code above in my browsers on my laptop at home, the latitudes and longitudes returned were scarily close to my home (albeit a street away). How do they do it? Firefox provides a nice FAQ about Firefox gelocation.


Disabling Browser Support for Gelocation Identification

The three browsers referenced in this post that support the Geolocation API meet the standard's requirement of requesting permission before providing location data:

A conforming implementation of this specification must provide a mechanism that protects the user's privacy and this mechanism should ensure that no location information is made available through this API without the user's express permission. ... User agents must not send location information to Web sites without the express permission of the user. User agents must acquire permission through a user interface, unless they have prearranged trust relationships with users.

These browsers also provide methods to turn off the capability as the default. I cover how to do this for each of these three browsers in the next section.

To control how Google Chrome handles providing of Geolocation data, click on the wrench icon in the upper right corner of the browser, select "Options", select "Under the Hood" tab, click on "Content settings ..." button, and select "Location". The three options are to always allow all sites access to location data, to be prompted for each site to request access each time it is requested, or to turn it off at all times for all sites. There is an "Exceptions..." button that can be clicked to specify exceptions to the bullet that turns it off for all sites at all times. This is demonstrated in the next screen snapshot.


Safari 5 allows the user to disable location services in general so that the user is not prompted every time a site requests location information. This is done by clicking on the wheel in the upper right corner ("Display a menu of general Safari settings"), selecting "Preferences", clicking on the "Security" lock icon, and unchecking the checkbox labeled "Location Services:" with the option "Allow websites to ask for location information". This is shown in the next screen snapshot.


The Firefox approach for controlling how and when location information is provided to requesting web sites is not difficult, but it does involve a little more effort than that for Safari or Chrome. The Firefox user types "about:config" (without the double quotes) in the field where URLs are typed. This leads to the warning shown in the next screen snapshot.


Bravery pays off here. When that button ("I'll be careful, I promise!") is clicked, a long list of Firefox configuration preferences is presented and they can be changed. The next screen snapshot only shows the configuration this blog post pertains to (geo.enabled), but numerous others are available as well. The values for this preference can be changed to the user's desire. The user clicks on that row and then right-clicks to get the choice of toggling the boolean value or resetting to the default (true). If the user did turn it off, the Status column indicates that the property is "user set". The screen snapshot that follows shows this more clearly.



Conclusion

The promise of a standardized approach to gelocation is exciting and provides developers an easier approach to making applications richer and more useful to the people using those applications. The standardized API makes developers' lives easier while also potentially benefiting users with location context-based information. This is a huge boon on mobile devices, but can be useful even for laptop and desktop browser users. Besides providing developers with a standard API for delivering features based on location services, another advantage of the Geolocation API is its calling out of compliant browsers' handling of privacy issues related to geolocation. It is comforting to know that major browsers will most likely comply.


Additional References

Dive Into HTML5: You Are Here (and So Is Everybody Else)

Mozilla Developer Center: Using Geolocation

HTML5 Geolocation API is Scaring Me

3 comments:

Lady Belle Rouge said...

Hi dustin,
i have tried geolocation on safari 5...it doesn't seem to be working...it always ask me if i want to share my current location and then tells me geolocation not successful...

@DustinMarx said...

I am using Safari 5.0.3 (7533.19.4) and it seems to be working okay for me. It does appear that others have run into issues using Safari's Geolocation capabilities. It appears that Safari uses Skyhook Wireless to detect geolocation as documented here.

If you run the example above do you get an error message starting with ERROR: followed by an error code?

Dustin

apilayer said...

Also the points out some of the benefits and limitations of the Geolocation API javascript. For example, the ability to retrieve a user's location can be useful for providing more targeted and personalized services to users, but it also raises privacy concerns, as users may not want to share their location with every website they visit.

Additionally, the notes that the accuracy of the Geolocation API can vary depending on the user's device and location and that developers need to be mindful of this when using the API to provide location-based services.