<pre class="metadata">
Title: Geolocation Sensor
Level: none
Status: ED
ED: https://w3c.github.io/geolocation-sensor/
TR: https://www.w3.org/TR/geolocation-sensor/
Previous Version: https://www.w3.org/TR/2018/WD-geolocation-sensor-20180821/
Shortname: geolocation-sensor
Editor: Anssi Kostiainen 41974, Intel Corporation, https://intel.com/
Editor: Thomas Steiner 44965, Google Inc., https://google.com/
Editor: Marijn Kruisselbrink, Google Inc., https://google.com/
Group: dap
Status Text: <p class="note" role="note"><span>Note:</span> The work on the Geolocation API [[GEOLOCATION-API]] has been concluded, and as such, any new feature development is happening in this Geolocation Sensor specification. The two specifications are expected to coexist.</p>
Abstract:
  This specification defines the {{GeolocationSensor}} interface for obtaining
  the [=geolocation=] of the hosting device.
!Participate: <a href="https://github.com/w3c/geolocation-sensor">GitHub</a> (<a href="https://github.com/w3c/geolocation-sensor/issues/new">new issue</a>, <a href="https://github.com/w3c/geolocation-sensor/issues">open issues</a>)
Indent: 2
Markup Shorthands: markdown on
Inline Github Issues: true
!Tests: <a href="https://github.com/web-platform-tests/wpt/tree/master/geolocation-sensor">web-platform-tests</a>
!Polyfills: <a href="https://github.com/kenchris/sensor-polyfills/blob/master/src/geolocation-sensor.js">geolocation-sensor.js</a><br><a href="https://github.com/w3c/sensors/blob/master/polyfills/geolocation.js">geolocation.js</a>
Boilerplate: omit issues-index, omit conformance, omit feedback-header
Ignored Vars: p, geo, key
Default Biblio Status: current
Note class: note
</pre>
<pre class="anchors">
urlPrefix: https://w3c.github.io/sensors; spec: GENERIC-SENSOR
  type: dfn
    text: high-level
    text: sensor
    text: latest reading
    text: default sensor
    text: construct a sensor object; url: construct-sensor-object
    text: initialize a sensor object; url: initialize-a-sensor-object
    text: sensor type
    text: security and privacy; url: security-and-privacy
    text: extensible; url: extensibility
    text: check sensor policy-controlled features; url: check-sensor-policy-controlled-features
    text: automation
    text: mock sensor type
    text: mock sensor reading values
urlPrefix: https://dom.spec.whatwg.org; spec: DOM
  type: dfn
    text: add the following abort steps; url: abortsignal-add
    text: aborted flag; url: abortsignal-aborted-flag
urlPrefix: http://w3c.github.io/hr-time/; spec: HR-TIME-2
  type: interface
    text: DOMHighResTimeStamp; url: dom-domhighrestimestamp
</pre>
</pre>
<pre class="biblio">
{
  "WGS84": {
    "authors": [
      "National Imagery and Mapping Agency"
    ],
    "href": "http://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf",
    "title": "Department of Defence World Geodetic System 1984",
    "status": "Technical Report, Third Edition",
    "publisher": "National Imagery and Mapping Agency"
  }
}
</pre>

Introduction {#intro}
============

The {{GeolocationSensor}} API extends the {{Sensor}} interface [[GENERIC-SENSOR]] to provide
information about the [=geolocation=] of the hosting device.

The feature set of the {{GeolocationSensor}} is similar to that of the Geolocation API
[[GEOLOCATION-API]], but it is surfaced through a modern API that is consistent across
<a href="https://www.w3.org/das/roadmap">contemporary sensor APIs</a>, improves
<a>security and privacy</a>, and is <a>extensible</a>. The API aims to be
<a href="https://github.com/kenchris/sensor-polyfills/blob/master/src/geolocation-sensor.js">polyfillable</a>
(<a href="https://kenchris.github.io/sensor-polyfills/run-geolocation.html">example</a>)
on top of the existing Geolocation API.

Examples {#examples}
========

<p>
  Get a new geolocation reading every second:
</p>
<div class="example">
  <pre highlight="js">
  const geo = new GeolocationSensor({ frequency: 1 });
  geo.start();

  geo.onreading = () => console.log(\`lat: ${geo.latitude}, long: ${geo.longitude}\`);

  geo.onerror = event => console.error(event.error.name, event.error.message);
  </pre>
</div>

<p>
  Get a one-shot geolocation reading:
</p>
<div class="example">
  <pre highlight="js">
  GeolocationSensor.read()
    .then(geo => console.log(\`lat: ${geo.latitude}, long: ${geo.longitude}\`))
    .catch(error => console.error(error.name));
  </pre>
</div>

Security and Privacy Considerations {#security-and-privacy}
===================================

Note: Investigate any geolocation-specific security and privacy considerations that are not
mitigated by the Generic Sensor API [[!GENERIC-SENSOR]], and define geolocation-specific
mitigations.

Model {#model}
=====

The term <dfn>geolocation</dfn> refers to the real-world geographic location of the
hosting device represented in geographic coordinates [[!WGS84]].

Note: An implementation can use multiple location information sources to acquire
<a>geolocation</a> information, and this specification is agnostic with respect
to those sources.

The <dfn>Geolocation Sensor</dfn> <a>sensor type</a>'s associated {{Sensor}} subclass is the
{{GeolocationSensor}} class.

The <a>Geolocation Sensor</a> has an associated {{PermissionName}} which is
<a for="PermissionName" enum-value>"geolocation"</a>.

A <dfn>latest geolocation reading</dfn> is a [=latest reading=] for a {{Sensor}} of
<a>Geolocation Sensor</a> <a>sensor type</a>. It includes [=map/entries=] whose [=map/keys=]
are "latitude", "longitude", "altitude", "accuracy", "altitudeAccuracy", "heading", "speed"
and whose [=map/values=] contain the device's [=geolocation=].

Note: Consider adding a visual of the standard coordinate system for the Earth.

API {#api}
===

The GeolocationSensor Interface {#geolocationsensor-interface}
-------------------------------

<pre class="idl">
  [Constructor(optional GeolocationSensorOptions options = {}),
   SecureContext,
   Exposed=(DedicatedWorker, Window)]
  interface GeolocationSensor : Sensor {
    static Promise&lt;GeolocationSensorReading&gt; read(optional ReadOptions readOptions = {});
    readonly attribute unrestricted double? latitude;
    readonly attribute unrestricted double? longitude;
    readonly attribute unrestricted double? altitude;
    readonly attribute unrestricted double? accuracy;
    readonly attribute unrestricted double? altitudeAccuracy;
    readonly attribute unrestricted double? heading;
    readonly attribute unrestricted double? speed;
  };

  dictionary GeolocationSensorOptions : SensorOptions {
    // placeholder for GeolocationSensor-specific options
  };

  dictionary ReadOptions : GeolocationSensorOptions {
    AbortSignal? signal;
  };

  dictionary GeolocationSensorReading {
    DOMHighResTimeStamp? timestamp;
    double? latitude;
    double? longitude;
    double? altitude;
    double? accuracy;
    double? altitudeAccuracy;
    double? heading;
    double? speed;
  };

</pre>

<div class="note">
Normative changes to the <code>
<a href="https://dev.w3.org/geo/api/spec-source.html#coordinates_interface">
Coordinates</a></code> interface of the Geolocation API are the following:
<ul>
  <li>Use <a href="https://heycam.github.io/webidl/#idl-unrestricted-double">
  unrestricted double</a> to not throw TypeError on NaN, +Infinity or −Infinity.
  (Geolocation API defines NaN as a valid value for heading, yet uses double as its type.)
  <li>Use <a href="https://heycam.github.io/webidl/#dfn-nullable-type">nullable</a> to allow
  all attributes to default to null. (Geolocation API does not provide synchronous means to
  access these attributes, thus latitude, longitude, and altitude are not nullable and "must be
  supported by all implementations".)
</ul>
</div>

To construct a {{GeolocationSensor}} object the user agent must invoke the
[=construct a geolocation sensor object=] abstract operation.

### GeolocationSensor.read() ### {#geolocationsensor-read}

The {{GeolocationSensor/read()}} method, when called, must run the following algorithm:

<div algorithm="read">
<!-- https://dom.spec.whatwg.org/#abortcontroller-api-integration -->

    : input
    :: |options|, a {{ReadOptions}} object.
    : output
    :: |p|, a promise.

    1. Let |p| be a new promise.
    1. Let |options| be the first argument.
    1. Let |signal| be the |options|' dictionary member of the same name if present, or null otherwise.
    1. If |signal|'s <a>aborted flag</a> is set, then reject |p| with an "{{AbortError!!exception}}" {{DOMException}} and return |p|.
    1. Let |geo| be the result of invoking <a>construct a Geolocation Sensor object</a> with |options|. If this throws a {{DOMException}}, catch it, reject |p| with that {{DOMException}}, and return |p|.
    1. Invoke |geo|.{{Sensor/start()}}.
    1. If |signal| is not null, then <a>add the following abort steps</a> to |signal|:
      1. Invoke |geo|.{{Sensor/stop()}}.
      1. Reject |p| with an "{{AbortError!!exception}}" {{DOMException}} and abort these steps.
    1. Run these steps <a>in parallel</a>:
      1. If <a>notify error</a> is invoked with |geo|, invoke |geo|.{{Sensor/stop()}}, and reject |p| with the {{DOMException}} passed as input to <a>notify error</a>.
      1. If <a>notify new reading</a> is invoked with |geo|, then <a>resolve a geolocation promise</a> with |geo| and |p|.
    1. Return |p|.
</div>

<p class="note">
Implementations can reuse the same promise for multiple concurrent calls within the same browsing context if the arguments passed to {{read()}} are the same.
</p>

To <dfn>resolve a geolocation promise</dfn> means to run the following steps:
  1. Let |reading| be a {{GeolocationSensorReading}}.
  1. [=set/For each=] |key| → |value| of <a>latest geolocation reading</a>:
    1. [=map/Set=] |reading|[key] to |value|.
  1. Invoke |geo|.{{Sensor/stop()}}.
  1. Resolve |p| with |reading|.


### GeolocationSensor.latitude ### {#geolocationsensor-latitude}

The {{GeolocationSensor/latitude!!attribute}} attribute of the {{GeolocationSensor}} interface
returns the result of invoking [=get value from latest reading=] with `this` and "latitude" as
arguments. It represents the latitude coordinate of the [=geolocation=] in decimal degrees
[[!WGS84]].

### GeolocationSensor.longitude ### {#geolocationsensor-longitude}

The {{GeolocationSensor/longitude!!attribute}} attribute of the {{GeolocationSensor}} interface
returns the result of invoking [=get value from latest reading=] with `this` and "longitude" as
arguments. It represents the longitude coordinate of the [=geolocation=] in decimal degrees
[[!WGS84]].

### GeolocationSensor.altitude ### {#geolocationsensor-altitude}

The {{GeolocationSensor/altitude!!attribute}} attribute of the {{GeolocationSensor}} interface
returns the result of invoking [=get value from latest reading=] with `this` and "altitude" as
arguments. It represents the [=geolocation=] in meters above the WGS 84 ellipsoid [[!WGS84]].

### GeolocationSensor.accuracy ### {#geolocationsensor-accuracy}

The {{GeolocationSensor/accuracy!!attribute}} attribute of the {{GeolocationSensor}} interface
returns the result of invoking [=get value from latest reading=] with `this` and "accuracy" as
arguments. It represents the accuracy of the [=latest reading=]["latitude"] value and
[=latest reading=]["longitude"] value in meters with a 95% confidence level.

If the [=latest reading=]["latitude"] value is null or [=latest reading=]["longitude"] value is
null, it must return null.

### GeolocationSensor.altitudeAccuracy ### {#geolocationsensor-altitudeaccuracy}

The {{GeolocationSensor/altitudeAccuracy!!attribute}} attribute of the {{GeolocationSensor}}
interface returns the result of invoking [=get value from latest reading=] with `this` and
"altitudeAccuracy" as arguments. It represents the accuracy of the
[=latest reading=]["altitude"] value in meters with a 95% confidence level.

If the [=latest reading=]["altitude"] value is null, it must return null.

### GeolocationSensor.heading ### {#geolocationsensor-heading}

The {{GeolocationSensor/heading!!attribute}} attribute of the {{GeolocationSensor}} interface
returns the result of invoking [=get value from latest reading=] with `this` and "heading" as
arguments. It represents the direction of travel in degrees counting clockwise relative to the
true north in the range 0 ≤ heading ≤ 360.

### GeolocationSensor.speed ### {#geolocationsensor-speed}

The {{GeolocationSensor/speed!!attribute}} attribute of the {{GeolocationSensor}} interface
returns the result of invoking [=get value from latest reading=] with `this` and "speed" as
arguments. It represents the magnitude of the horizontal component of the velocity in meters
per second.

Abstract Operations {#abstract-operations}
===================

<h3 dfn export>Construct a geolocation sensor object</h3>

<div algorithm="construct a geolocation sensor object">

    : input
    :: |options|, a {{GeolocationSensorOptions}} object.
    : output
    :: A {{GeolocationSensor}} object.

    1.  Let |allowed| be the result of invoking [=check sensor policy-controlled features=]
        with {{GeolocationSensor}}.
    1.  If |allowed| is false, then:
        1.  [=Throw=] a {{SecurityError}} {{DOMException}}.
    1.  Let |geo| be the new {{GeolocationSensor}} object.
    1.  Invoke [=initialize a sensor object=] with |geo| and |options|.
    1.  Return |geo|.
</div>

Automation {#automation}
==========
This section extends the [=automation=] section defined in the Generic Sensor API [[GENERIC-SENSOR]]
to provide mocking information about the [=geolocation=] of the hosting device for the purposes of
testing a user agent's implementation of {{GeolocationSensor}} API.

<h3 id="mock-geolocation-sensor-type">Mock Sensor Type</h3>

The {{GeolocationSensor}} class has an associated [=mock sensor type=] which is
<a for="MockSensorType" enum-value>"geolocation"</a>, its [=mock sensor reading values=]
dictionary is defined as follows:

<pre class="idl">
  dictionary GeolocationReadingValues {
    required double? latitude;
    required double? longitude;
    required double? altitude;
    required double? accuracy;
    required double? altitudeAccuracy;
    required double? heading;
    required double? speed;
  };
</pre>

Use Cases {#use-cases}
=========

## Categorization of use cases ## {#use-cases-categorization}

The mentioned use cases can roughly be grouped into four categories:

* **Foreground** operations:
  * Getting a **one-off geolocation update**.
  * Getting **continuous geolocation updates** (*aka.* foreground geotracking).
* **Background** operations:
  * Getting **continuous geolocation updates** (*aka.* background geotracking).
  * Getting a **one-off geolocation fence alert** (*aka.* background geofencing).

Note: Only the **foreground operations** were possible with [[GEOLOCATION-API]],
the **background operations** are completely novel.

Core constraints when obtaining the gelocation are **accuracy** (*how close to the
actual position of the user is the determined position*) and **latency**
(*how long does the user want to wait for a result*). Both are tradeoffs:
one can trade faster results for lower accuracy and vice versa.

A common theme is to first obtain a rough estimation that then gets refined over time,
for example based initially on surrounding WiFi signals (which is fast to obtain)
and then eventually based on precise GPS data (which may take some time to find a signal).

In the following, we list use cases based on the previously defined categories.

Note: The categories are not mutually exclusive and overlaps exist.
A task might start in the foreground, then continue in the background (for example,
while the user quickly responds to an incoming email),
and then eventually terminate in the foreground when the user multitasks back.

## Foreground—One-off geolocation update ## {#use-cases-foreground-one-off}

### Locate a user on a map ### {#use-case-locate-a-user-on-a-map}

A mapping application can use the Geolocation Sensor API data of a user to locate them
on the map, essentially responding to the question "Where am I right now?"

### Find points of interest in the user's area ### {#use-case-find-points-of-interest-in-the-users-area}

Someone visiting a foreign city could access a web application that allows users
to search or browse through a database of tourist attractions. Using the Geolocation Sensor API,
the web application has access to the user's approximate current position
and is therefore able to rank the search results by proximity to the user's location.

## Foreground—Continuous geolocation updates ## {#use-cases-foreground-continuous}

### Up-to-date local information ### {#use-case-up-to-date-local-information}

A widget-like web application that shows the weather or news that are relevant
to the user's current area can use the Geolocation Sensor API to register for location updates.
If the user's position changes, the widget can adapt the content accordingly.

### Alerts when points of interest are in the user's vicinity ### {#use-case-alerts-when-points-of-interest-are-in-the-users-vicinity}

A tour guide web application can use the Geolocation Sensor API to monitor the user's position
and trigger visual or audio notifications when interesting places are in the vicinity.
An online task management system can trigger reminders when the user is in the proximity
of landmarks that are associated with certain tasks.
This use case assumes active usage of the application in the foreground.

### Show the user's position on a map ### {#use-case-show-the-users-position-on-a-map}

A user finds themselves in an unfamiliar area. They want to check their position
so they use their handheld device to navigate to a web-based mapping application
that can pinpoint their exact location on the map using the Geolocation Sensor API.
They then ask the web application to provide driving directions from their current position
to their desired destination, essentially responding to the question "Where am I going?".

## Background—Continuous geolocation updates ## {#use-cases-background-continuous}

### Location-tagged status updates in social networking applications ### {#use-case-location-tagged-status-updates-in-social-networking-applications}

A social networking application allows its users to automatically tag their status updates with
location information. It does this by monitoring the user's position with the Geolocation Sensor API.
Each user can control the granularity of the location information (e.g., city or neighborhood level)
that is shared with the other users. Any user can also see their network of friends
and get real-time updates about their current location,
granted they have opted in to their location data being shared.
This use case intentionally conflates foreground location tagging and background location sharing.

### Turn-by-turn route navigation ### {#use-case-turn-by-turn-route-navigation}

A mapping application can help the user navigate along a routeby providing detailed turn-by-turn directions.
The application does this by registering with the Geolocation Sensor API to receive
repeated location updates of the user's position. These updates are delivered as soon as the implementing
user agent determines that the position of the user has changed, which allows the application
to anticipate any changes of direction that the user might need to do.
The application can be in the foreground, but likewise can be backgrounded, for example,
when the user turns their device off to save battery on a long highway route section without side roads.

### Tracking sports activity ### {#use-case-tracking-sports-activity}

A web application can track a user's sports activity, for example, a marathon run or a bicycle race.
Therefore, the application does not need to be on the screen, but would be backgrounded
while the user performs their activity, maybe with their handheld device strapped to their arm.

### Real estate search ### {#use-case-real-estate-search}

A web application on a handheld device can notify a user of interesting available properties
in a neighborhood they are passing by where the property fits the user's previously specified search criteria,
for example, 3 bedroom apartments with balcony.
This is based on the assumption that the number of possible matches is high,
that is, impossible to realize with geofences as the amount of required geofences would be too high.

## Background—One-off geolocation fence alert ## {#use-cases-background-geofence}

### Reminder and to-do applications ### {#use-case-reminder-and-todo-applications}

Reminder and to-do web applications can use a geofence to remind the user to do something when they cross it,
for example, to buy milk when they are near the supermarket.

### Travel applications ### {#use-case-travel-applications}

Travel applications can show venue specific data like WiFi passwords,
the user's booking confirmation etc. only within geofence boundaries.

### Ticketing or booking confirmations ### {#use-case-ticketing-or-booking-confirmations}

Ticketing or booking applications can bring up a ticket notification with a QR or bar code
once the user is near the venue of a concert or sports event or when they reach their rental car counter or similar.

### Ride share applications ### {#use-case-ride-share-applications}

Users can be informed if their designated driver reaches a pre-defined pickup point.

### Retail special offers ### {#use-case-retail-special-offers}

Given their previous consent, a user with a retailer's web application installed on their handheld device
can be alerted about special offers or location-based coupons when they are
in vicinity of a physical presence of the retailer. Further, the in-store experience can be enriched,
for example, the retailer can let the user know something they have looked at before is actually available for pick up nearby.

Acknowledgements {#acknowledgements}
================

Thanks to Tobie Langel for the work on Generic Sensor API and the early geolocation.js polyfill.

Thanks to Kenneth Rohde Christiansen for the geolocation-sensor.js polyfill and design proposals
during the incubation phase.

Special thanks to the Geolocation Working Group participants for their work on the Geolocation API
from 2008 until 2017.
