Using geolocation

  • Revision slug: Using_geolocation
  • Revision title: Using geolocation
  • Revision id: 297657
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment

Revision Content

{{ DevDerbyPromoHeader("Geolocation") }}

Firefox 3.5 and later support the Geolocation API; this allows the user to provide their location to web applications if they so desire.  For privacy reasons, the user is asked to confirm permission to report location information.

Firefox 3.5 includes support for locating you based on your WiFi information using Google Location Services. In the transaction between Firefox 3.5 and Google, data is exchanged including WiFi Access Point data, an access token (similar to a 2 week cookie), and the user's IP address.  For more information, please check out Mozilla's Privacy Policy and Google's Privacy Policy covering how this data can be used.  Also see the source code if you're curious how this service is implemented.

Note: If your interest is in writing a geolocation provider -- a service which can be queried for the user's location -- please see {{ Interface("nsIGeolocationProvider") }}.  You may also find the WiFi access point monitoring service interesting.

Firefox 3.6 (Gecko 1.9.2) added support for using the GPSD (GPS daemon) service for geolocation on Linux.

Note: Extensions hosted on addons.mozilla.org must explicitly request permission before accessing geolocation data.

The geolocation object

The geolocation API is published through a geolocation child object within the navigator object.  If the object exists, geolocation services are available.  You can test for the presence of geolocation thusly:

if ("geolocation" in navigator) {
  /* geolocation is available */
} else {
  alert("I'm sorry, but geolocation services are not supported by your browser.");
}

{{ gecko_minversion_header("1.9.2") }}

Starting in Gecko 1.9.2 (Firefox 3.6), add-ons can obtain the geolocation object by obtaining a reference to the geolocation service like this:

var geolocation = Components.classes["@mozilla.org/geolocation;1"]
                            .getService(Components.interfaces.nsIDOMGeoGeolocation);

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, a specified callback routine is executed.  You can optionally provide a second callback to be executed if an error occurs.  A third, optional, parameter is an options interface where you can set the maximum age of the position returned and the time to wait for a request.

Use getCurrentPosition() if you want a single position fix ASAP, regardless of the accuracy. Devices with a GPS, for example, can take a minute or more to get a GPS fix, so less accurate data (IP location or wifi) may be returned to getCurrentPosition() to start.

navigator.geolocation.getCurrentPosition(function(position) {
  do_something(position.coords.latitude, position.coords.longitude);
});

The above example will cause the do_something() function to execute when the location is obtained.

Watching the current position

If the position data changes (either by device movement or if more accurate geo information arrives) , you can set up a callback that is called with that updated position information.  This is done using the watchPosition() function, which has the same input parameters as getCurrentPosition().  Its callback is called multiple times, allowing the browser to either update your location as you move, or provide a more accurate location as different techniques are used to geolocate you.  The error callback, which is optional just as it is for getCurrentPosition(), is called only once, if there will never be valid results returned.

You can use watchPosition() without an initial getCurrentPosition() call.

var watchID = navigator.geolocation.watchPosition(function(position) {
  do_something(position.coords.latitude, position.coords.longitude);
}
);

The watchPosition() method returns an ID number that can be used to uniquely identify the requested position watcher; you use this value in tandem with the clearWatch() method to stop watching the user's location.

navigator.geolocation.clearWatch(watchID);

watchPosition() accepts a success callback and error callback (like getCurrentPosition) and an optional positionObjects object, which can have three properties:

  • enableHighAccuracy – A boolean which indicates to the device that you wish to obtain it’s most accurate readings (this parameter may or may not make a difference, depending on your hardware)
  • maximumAge – The maximum age (in milliseconds) of the reading (this is appropriate as the device may cache readings to save power and/or bandwidth)
  • timeout – The maximum time (in milliseconds) for which you are prepared to allow the device to try to obtain a Geo location

A call to watchPosition could look like:

var wpid = navigator.geolocation.watchPosition(geo_success, geo_error, {enableHighAccuracy:true, maximumAge:30000, timeout:27000});

A demo of watchPosition in use: http://www.thedotproduct.org/experiments/geo/


Describing a position

The user's location is described using a Position object, which has the following fields:

timestamp
The time at which the reading was taken, as a DOMTimeStamp.
coords
An nsIDOMGeoPositionCoords object indicating the location.
address {{ gecko_minversion_inline("1.9.2") }} {{obsolete_inline("14.0")}}
An {{ interface("nsIDOMGeoPositionAddress") }} object specifying the corresponding address, if available.

Handling errors

The error callback, if provided when calling getCurrentPosition() or watchPosition(), has the following signature:

function errorCallback(PositionError error);

The PositionError structure has the following fields:

code
A numeric error code which much be one of the following:
UNKNOWN_ERROR (numeric value 0)
The location acquisition process failed due to an error not covered by the definition of any other error code in this interface.
PERMISSION_DENIED (numeric value 1)
The location acquisition process failed because the application origin does not have permission to use the Geolocation API.
POSITION_UNAVAILABLE (numeric value 2)
The position of the device could not be determined. One or more of the location providers used in the location acquisition process reported an internal error that caused the process to fail entirely.
TIMEOUT (numeric value 3)
The specified maximum length of time has elapsed before the implementation could successfully acquire a new Position object.
 
message
A human readable error message, suitable for use in logs and debugging -- but not for display to the user.

Browser compatibility

Browser Basic support Geolocation Level 2
Internet Explorer IE9 RC ---
Firefox (Gecko) 3.5 (1.9.1) ---
Opera 10.60 ---
Safari | Chrome | WebKit 5 | 5 | 533 ---

Prompting for permission

Any add-on hosted on addons.mozilla.org which makes use of geolocation data must explicitly request permission before doing so. The following function will request permission in a manner similar to the automatic prompt displayed for web pages. The user's response will be saved in the preference specified by the pref parameter, if applicable. The function provided in the callback parameter will be called with a boolean value indicating the user's response. If true, the add-on may access geolocation data.

function prompt(window, pref, message, callback) {
  let branch = Components.classes["@mozilla.org/preferences-service;1"]
               .getService(Components.interfaces.nsIPrefBranch2);
  if (branch.getPrefType(pref) === branch.PREF_STRING) { 
    switch (branch.getCharPref(pref)) { 
      case "always": return callback(true); 
      case "never": return callback(false); 
    } 
  }

  let done = false; 
  function remember(value, result) { 
    return function () { 
      done = true; 
      branch.setCharPref(pref, value); 
      callback(result); 
    } 
  }

  let self = window.PopupNotifications.show(window.gBrowser.selectedBrowser, 
                                            "geolocation", 
                                            message, 
                                            "geo-notification-icon", 
                                            { 
                                              label: "Share Location", 
                                              accessKey: "S", 
                                              callback: function (notification) { 
                                                done = true; callback(true); 
                                              } 
                                            }, 
                                            [{
                                                label: "Always Share", 
                                                accessKey: "A", 
                                                callback: remember("always", true) 
                                              }, { 
                                                label: "Never Share", 
                                                accessKey: "N", 
                                                callback: remember("never", false) 
                                            }], 
                                            { 
                                              eventCallback: function (event) { 
                                                if (event === "dismissed") { 
                                                  if (!done) callback(false); 
                                                  done = true; 
                                                  window.PopupNotifications.remove(self); 
                                                } 
                                              }, 
                                              persistWhileVisible: true 
                                            }); 
}

prompt(window, 
       "extensions.foo-addon.allowGeolocation", 
       "Foo Add-on wants to know your location.", 
       function callback(allowed) { alert(allowed) });

See also

  • {{ Interface("nsIGeolocationProvider") }}
  • {{ Interface("nsIDOMGeolocation") }}
  • {{ Interface("nsIDOMGeoPosition") }}
  • {{ Interface("nsIDOMGeoPositionCallback") }}
  • {{ Interface("nsIDOMGeoPositionError") }}
  • {{ Interface("nsIDOMGeoPositionErrorCallback") }}
  • {{ Interface("nsIDOMGeoPositionOptions") }}
  • {{ Interface("nsIDOMNavigatorGeolocation") }}
  • Geolocation API on w3.org
  • Demos about the Geolocation API

{{ HTML5ArticleTOC() }}

Revision Source

<p>{{ DevDerbyPromoHeader("Geolocation") }}</p>
<p>Firefox 3.5 and later support the Geolocation API; this allows the user to provide their location to web applications if they so desire.&nbsp; For privacy reasons, the user is asked to confirm permission to report location information.</p>
<p>Firefox 3.5 includes support for locating you based on your WiFi information using Google Location Services. In the transaction between Firefox 3.5 and Google, data is exchanged including WiFi Access Point data, an access token (similar to a 2 week cookie), and the user's IP address.&nbsp; For more information, please check out Mozilla's <a class="external" href="http://www.mozilla.com/en-US/legal/privacy/" title="http://www.mozilla.com/en-US/legal/privacy/">Privacy Policy</a> and Google's <a class="external" href="http://www.google.com/privacy-lsf.html" title="http://www.google.com/privacy-lsf.html">Privacy Policy</a> covering how this data can be used.&nbsp; Also see the <a class="external" href="http://mxr.mozilla.org/mozilla1.9.1/source/dom/src/geolocation/NetworkGeolocationProvider.js" title="http://mxr.mozilla.org/mozilla1.9.1/source/dom/src/geolocation/NetworkGeolocationProvider.js">source code</a> if you're curious how this service is implemented.</p>
<div class="note">
  <strong>Note:</strong> If your interest is in writing a geolocation provider -- a service which can be queried for the user's location -- please see {{ Interface("nsIGeolocationProvider") }}.&nbsp; You may also find the <a class="internal" href="/En/Monitoring_WiFi_access_points" title="En/Monitoring WiFi access points">WiFi access point monitoring service</a> interesting.</div>
<p>Firefox 3.6 (Gecko 1.9.2) added support for using the <a class="external" href="http://catb.org/gpsd/" title="http://catb.org/gpsd/">GPSD</a> (GPS&nbsp;daemon)&nbsp;service for geolocation on Linux.</p>
<div class="note">
  <strong>Note:</strong> Extensions hosted on addons.mozilla.org must explicitly <a href="#request-permission">request permission</a> before accessing geolocation data.</div>
<h2 id="The_geolocation_object">The geolocation object</h2>
<p>The geolocation API&nbsp;is published through a <code>geolocation</code> child object within the <code>navigator</code> object.&nbsp; If the object exists, geolocation services are available.&nbsp; You can test for the presence of geolocation thusly:</p>
<pre class="brush: js">
if ("geolocation" in navigator) {
  /* geolocation is available */
} else {
&nbsp; alert("I'm sorry, but geolocation services are not supported by your browser.");
}
</pre>
<p>{{ gecko_minversion_header("1.9.2") }}</p>
<p>Starting in Gecko 1.9.2 (Firefox 3.6), add-ons can obtain the geolocation object by obtaining a reference to the geolocation service like this:</p>
<pre class="brush: js">
var geolocation = Components.classes["@mozilla.org/geolocation;1"]
                            .getService(Components.interfaces.nsIDOMGeoGeolocation);
</pre>
<h3 id="Getting_the_current_position">Getting the current position</h3>
<p>To obtain the user's current location, you can call the <code>getCurrentPosition()</code>&nbsp;method.&nbsp; This initiates an asynchronous request to detect the user's position, and queries the positioning hardware to get up-to-date information.&nbsp; When the position is determined, a specified callback routine is executed.&nbsp; You can optionally provide a second callback to be executed if an error occurs.&nbsp; A third, optional, parameter is an options interface where you can set the maximum age of the position returned and the time to wait for a request.</p>
<p>Use <code>getCurrentPosition()</code> if you want a single position fix ASAP, regardless of the accuracy.&nbsp;Devices with a GPS, for example, can take a minute or more to get a GPS fix, so less accurate data (IP location or wifi)&nbsp;may be returned to <code>getCurrentPosition()</code> to start.</p>
<pre class="brush: js">
navigator.geolocation.getCurrentPosition(function(position) {
&nbsp;&nbsp;do_something(position.coords.latitude, position.coords.longitude);
});</pre>
<p>The above example will cause the <code>do_something()</code> function to execute when the location is obtained.</p>
<h3 id="Watching_the_current_position">Watching the current position</h3>
<p>If the position data changes (either by device movement or if more accurate geo information arrives) , you can set up a callback that is called with that updated position information.&nbsp; This is done using the <code>watchPosition()</code>&nbsp;function, which has the same input parameters as <code>getCurrentPosition()</code>.&nbsp; Its callback is called multiple times, allowing the browser to either update your location as you move, or provide a more accurate location as different techniques are used to geolocate you. &nbsp;The error callback, which is optional just as it is for <code>getCurrentPosition()</code>, is called only once, if there will never be valid results returned.</p>
<p>You can use <code>watchPosition()</code> without an initial <code>getCurrentPosition() </code>call.</p>
<pre class="brush: js">
var watchID&nbsp;= navigator.geolocation.watchPosition(function(position) {
&nbsp;&nbsp;do_something(position.coords.latitude, position.coords.longitude);
}
);</pre>
<p>The <code>watchPosition()</code> method returns an ID&nbsp;number that can be used to uniquely identify the requested position watcher; you use this value in tandem with the <code>clearWatch()</code>&nbsp;method to stop watching the user's location.</p>
<pre>
navigator.geolocation.clearWatch(watchID);
</pre>
<p><code>watchPosition() </code>accepts a success callback and error callback (like <code>getCurrentPosition</code>) and an optional <code>positionObjects</code> object, which can have three properties:</p>
<ul>
  <li><code>enableHighAccuracy</code> – A boolean which indicates to the device that you wish to obtain it’s most accurate readings (this parameter may or may not make a difference, depending on your hardware)</li>
  <li><code>maximumAge</code> – The maximum age (in milliseconds) of the reading (this is appropriate as the device may cache readings to save power and/or bandwidth)</li>
  <li><code>timeout</code> – The maximum time (in milliseconds) for which you are prepared to allow the device to try to obtain a Geo location</li>
</ul>
<p>A call to watchPosition could look like:</p>
<pre>
var wpid = navigator.geolocation.watchPosition(geo_success, geo_error, {enableHighAccuracy:true, maximumAge:30000, timeout:27000});</pre>
<p><a id="fck_paste_padding">A demo of watchPosition in use:&nbsp;</a><a class="external" href="http://www.thedotproduct.org/experiments/geo/">http://www.thedotproduct.org/experiments/geo/</a><br />
  <a id="fck_paste_padding"></a></p>
<h2 id="Describing_a_position">Describing a position</h2>
<p>The user's location is described using a Position object, which has the following fields:</p>
<dl>
  <dt>
    timestamp</dt>
  <dd>
    The time at which the reading was taken, as a <code>DOMTimeStamp</code>.</dd>
  <dt>
    coords</dt>
  <dd>
    An <a class="internal" href="/en/XPCOM_Interface_Reference/NsIDOMGeoPositionCoords" title="En/NsIDOMGeoPositionCoords"><code>nsIDOMGeoPositionCoords</code></a> object indicating the location.</dd>
  <dt>
    address {{ gecko_minversion_inline("1.9.2") }} {{obsolete_inline("14.0")}}</dt>
  <dd>
    An {{ interface("nsIDOMGeoPositionAddress") }} object specifying the corresponding address, if available.</dd>
</dl>
<h2 id="Handling_errors">Handling errors</h2>
<p>The error callback, if provided when calling <code>getCurrentPosition()</code>&nbsp;or <code>watchPosition()</code>, has the following signature:</p>
<pre>
function errorCallback(PositionError error);
</pre>
<p>The <code>PositionError</code> structure has the following fields:</p>
<dl>
  <dt>
    code</dt>
  <dd>
    A numeric error code which much be one of the following:</dd>
  <dt>
    <dfn id="unknown_error"><code>UNKNOWN_ERROR</code></dfn> (numeric value 0)</dt>
  <dd>
    The location acquisition process failed due to an error not covered by the definition of any other error code in this interface.</dd>
  <dt>
    <dfn id="permission_denied_error"><code>PERMISSION_DENIED</code></dfn> (numeric value 1)</dt>
  <dd>
    The location acquisition process failed because the application origin does not have permission to use the Geolocation API.</dd>
  <dt>
    <dfn id="position_unavailable_error"><code>POSITION_UNAVAILABLE</code></dfn> (numeric value 2)</dt>
  <dd>
    The position of the device could not be determined. One or more of the location providers used in the location acquisition process reported an internal error that caused the process to fail entirely.</dd>
  <dt>
    <dfn id="timeout_error"><code>TIMEOUT</code></dfn> (numeric value 3)</dt>
  <dd>
    The specified maximum length of time has elapsed before the implementation could successfully acquire a new Position object.</dd>
  <dd>
    &nbsp;</dd>
  <dt>
    message</dt>
  <dd>
    A human readable error message, suitable for use in logs and debugging -- but not for display to the user.</dd>
</dl>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<table class="standard-table">
  <tbody>
    <tr>
      <th>Browser</th>
      <th>Basic support</th>
      <th><a class="external" href="http://dev.w3.org/geo/api/spec-source-v2.html">Geolocation Level 2</a></th>
    </tr>
    <tr>
      <td>Internet Explorer</td>
      <td>IE9 RC</td>
      <td>---</td>
    </tr>
    <tr>
      <td>Firefox (Gecko)</td>
      <td><strong>3.5</strong> (1.9.1)</td>
      <td>---</td>
    </tr>
    <tr>
      <td>Opera</td>
      <td><strong>10.60</strong></td>
      <td>---</td>
    </tr>
    <tr>
      <td>Safari | Chrome | WebKit</td>
      <td>5 | 5 | 533</td>
      <td>---</td>
    </tr>
  </tbody>
</table>
<h2 id="Prompting_for_permission">Prompting for permission</h2>
<p>Any add-on hosted on addons.mozilla.org which makes use of geolocation data must explicitly request permission before doing so. The following function will request permission in a manner similar to the automatic prompt displayed for web pages. The user's response will be saved in the preference specified by the <code>pref</code> parameter, if applicable. The function provided in the <code>callback</code> parameter will be called with a boolean value indicating the user's response. If <code>true</code>, the add-on may access geolocation data.</p>
<pre class="brush: js">
function prompt(window, pref, message, callback) {
  let branch = Components.classes["@mozilla.org/preferences-service;1"]
               .getService(Components.interfaces.nsIPrefBranch2);
  if (branch.getPrefType(pref) === branch.PREF_STRING) { 
    switch (branch.getCharPref(pref)) { 
      case "always": return callback(true); 
      case "never": return callback(false); 
    } 
  }

  let done = false; 
  function remember(value, result) { 
    return function () { 
      done = true; 
      branch.setCharPref(pref, value); 
      callback(result); 
    } 
  }

  let self = window.PopupNotifications.show(window.gBrowser.selectedBrowser, 
                                            "geolocation", 
                                            message, 
                                            "geo-notification-icon", 
                                            { 
                                              label: "Share Location", 
                                              accessKey: "S", 
                                              callback: function (notification) { 
                                                done = true; callback(true); 
                                              } 
                                            }, 
                                            [{
                                                label: "Always Share", 
                                                accessKey: "A", 
                                                callback: remember("always", true) 
                                              }, { 
                                                label: "Never Share", 
                                                accessKey: "N", 
                                                callback: remember("never", false) 
                                            }], 
                                            { 
                                              eventCallback: function (event) { 
                                                if (event === "dismissed") { 
                                                  if (!done) callback(false); 
                                                  done = true; 
                                                  window.PopupNotifications.remove(self); 
                                                } 
                                              }, 
                                              persistWhileVisible: true 
                                            }); 
}

prompt(window, 
       "extensions.foo-addon.allowGeolocation", 
       "Foo Add-on wants to know your location.", 
       function callback(allowed) { alert(allowed) });
</pre>
<h2 id="See_also">See also</h2>
<ul>
  <li>{{ Interface("nsIGeolocationProvider") }}</li>
  <li>{{ Interface("nsIDOMGeolocation") }}</li>
  <li>{{ Interface("nsIDOMGeoPosition") }}</li>
  <li>{{ Interface("nsIDOMGeoPositionCallback") }}</li>
  <li>{{ Interface("nsIDOMGeoPositionError") }}</li>
  <li>{{ Interface("nsIDOMGeoPositionErrorCallback") }}</li>
  <li>{{ Interface("nsIDOMGeoPositionOptions") }}</li>
  <li>{{ Interface("nsIDOMNavigatorGeolocation") }}</li>
  <li><a class="external" href="http://dev.w3.org/geo/api/spec-source.html" title="http://dev.w3.org/geo/api/spec-source.html">Geolocation API on w3.org</a></li>
  <li><a href="/en-US/demos/tag/tech:geolocation" title="https://developer.mozilla.org/en-US/demos/tag/tech:geolocation/">Demos about the Geolocation API</a></li>
</ul>
<p>{{ HTML5ArticleTOC() }}</p>
<!-- languages( { "es": "es/Usar_la_Geolocalización",&nbsp; "ja": "ja/Using_geolocation" } ) -->
Revert to this revision