Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
This specification defines an API that lets webapps setup geographic boundaries around specific locations and then receive notifications when the hosting device enters or leaves those areas.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document was published by the Geolocation Working Group as a First Public Working Draft.
The Working Group expects to advance this Working Draft to Recommendation Status.
If you wish to make comments regarding this document, please send them to
public-geolocation@w3.org
(subscribe,
archives)
with [Geofencing API]
at the start of your email's subject.
All comments are welcome.
Publication as a First Public Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 August 2014 W3C Process Document.
This section is non-normative.
The Geofencing API lets webapps setup geographic boundaries around specific locations and then receive notifications when the hosting device enters or leaves those areas. While it would be possible to implement something similar using the Geolocation API [GEOLOCATION-API], there are a few differences that could make this API a better choice:
The following code extracts illustrate how to use this API to be notified of geographic regions being entered or left.
// https://example.com/webapp.js navigator.serviceWorker .register('serviceworker.js') .then((swRegistration) => { let region = new CircularGeofenceRegion({ name: 'myfence', latitude: 37.421999, longitude: -122.084015, radius: 1000 }); let options = { includePosition: true }; swRegistration.geofencing.add(region, options) .then( // If more than just a name needs to be stored with a geofence, now // would be the time to store this in some storage. (geofence) => console.log(geofence.id), (error) => console.log(error) ); });
// https://example.com/serviceworker.js self.ongeofenceenter = (event) => { console.log(event.geofence.id); console.log(event.geofence.region.name); // If this is not a geofence of interest anymore, remove it. if (event.geofence.region.name !== "myfence") { event.waitUntil(event.geofence.remove()); } };
// https://example.com/serviceworker.js self.ongeofenceerror = (event) => { console.log(event.geofence.id); console.log(event.geofence.region.name); console.log(event.error); // Some error condition occurred. The region is no longer monitored, and won't // trigger any more events. // Try to re-monitor, although depending on the error this might fail. event .waitUntil(self.registration.geofencing.add(event.geofence.region)) .then((geofence) => { // re-monitoring succeeded, new geofence will have a different ID. }, (error) => { // re-monitoring failed. }); };
// https://example.com/serviceworker.js // Either look geofence up by name: self.onsomeevent = (event) => { event .waitUntil( self.registration.geofencing.getAll({ name: 'myfence' }) ) .then( geofences => geofences.forEach(fence => fence.remove()) ); }; // Or look geofence up by ID: self.onsomeotherevent = (event) => { let geofence_id = ''; /* somehow get the ID of a geofence */ event .waitUntil(self.registration.geofencing.getById(geofence_id)) .then(geofence => geofence.remove()); };
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, SHOULD, and SHOULD NOT are to be interpreted as described in [RFC2119].
This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.
Implementations that use ECMAScript to implement the APIs defined in this specification MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [WEBIDL].
The geographic coordinate reference system used by the attributes in this API is the World Geodetic System (2d) [WGS84]. No other reference system is supported.
The terms event handler, event handler event type, queue a task, and fire a simple event are defined in [HTML5].
The types Promise
,
and
RangeError
are defined in [ECMASCRIPT].
EventInit
,
DOMException
,
InvalidStateError
,
NotFoundError
,
QuotaExceededError
,
SyntaxError
,
and steps for
constructing events are defined in [DOM].
The terms service
worker, service worker
registration, installing
worker, waiting worker,
and active
worker, and the types ServiceWorkerRegistration
,
ServiceWorkerGlobalScope
,
ExtendableEvent
,
and ExtendableEventInit
are defined in [SERVICE-WORKERS].
The type Position
is defined in [GEOLOCATION-API].
The term webapp refers to a Web application, i.e. an application implemented using Web technologies, and executing within the context of a Web user agent, e.g. a Web browser or other Web runtime environment.
The term geofence is used to refer to one specific registration of a geographic region as a geofence. A geofence is a tuple consisting of a geographic region, geofence ID and a include position flag.
A geofence ID is a string uniquely identifying a geofence. This ID is generated by the user agent and MUST be unique among all active geofences associated with all service worker registrations at the same origin. A user agent SHOULD NOT reuse the ID from an old geofence for a new one.
The term active geofences is used to refer to the collection of geofences associated with a particular service worker registration, that are currently being monitored by the user agent for breach events.
A geofence is said to be breached if the current geographical location changed from being inside the geographic region to outside (a leave event), or vice versa (an enter event).
The same security and privacy considerations that apply to the Geolocation API [GEOLOCATION-API] also apply to this API. Furthermore since this API effectively gives access to geographic location information after a user has stopped interacting with a webapp, a few other considerations should be taken into account.
TODO
TODO
This section is non-normative.
TODO
ServiceWorkerRegistration
interface
The Service Worker specification defines a ServiceWorkerRegistration
interface, which
this specification extends.
partial interface ServiceWorkerRegistration {
readonly attribute GeofenceManager
geofencing;
};
GeofenceManager
interface
The
interface defines operations that enable
webapps to establish access to geofencing services.
GeofenceManager
dictionary GeofenceQueryOptions {
DOMString? name;
};
dictionary GeofenceOptions {
boolean includePosition = false;
};
[NoInterfaceObject]
interface GeofenceManager {
Promise<Geofence
> add (GeofenceRegion
initialRegion, optional GeofenceOptions
options);
Promise<sequence<Geofence
>> getAll (optional GeofenceQueryOptions
options);
Promise<Geofence
> getById (DOMString id);
};
The
add
method when invoked MUST run the following steps:
Promise
.
DOMException
whose name is
"QuotaExceededError
" and terminate these substeps. A user
agent SHOULD allow at least 20 active geofences for an origin.
DOMException
whose name is "PermissionDeniedError
" and terminate these
substeps.
GeofenceRegion
instance of the same type and with the same
attributes as the initialRegion passed to add
.
false
if no options were
specified.
Geofence
instance
representing the geofence.
Somehow mention that the region that is saved as part of the registration can be slightly different from the region passed to register. An implementation may adjust parameters to be in range of what is possible, or otherwise modify the region.
The iOS API takes a slightly different approach when permission is denied. It instead always treats registrations as a success, but won't actually track geofences/trigger events unless the user has granted permission.
If the includePosition
attribute is set to true,
s for this registration will
have a GeofenceEvent
position
attribute. When
set to false, the position
attribute will always be undefined.
The getAll
method when invoked MUST run the following steps:
Promise
.
Geofence
instance
representing the geofence.
The getById
method
when invoked MUST run the following steps:
Promise
.
Geofence
instance with
attributes equal to those of the geofence.
null
.
Geofence
interface
An instance of the Geofence
interface represents a geofence.
interface Geofence {
readonly attribute DOMString id;
readonly attribute GeofenceRegion
region;
Promise<boolean> remove ();
};
When getting the id
attribute, the user
agent MUST return the geofence ID of the geofence.
When getting the region
attribute, the
user agent MUST return the geographic region of this geofence.
The remove
method when
invoked MUST run the following steps:
Promise
.
false
and abort the remainder of these steps.
true
.
GeofenceRegion
interface
dictionary GeofenceRegionInit {
DOMString? name;
};
[Exposed=(Window,Worker)]
interface GeofenceRegion {
readonly attribute DOMString name;
};
The name
attribute MUST return the value it was
initialized to. When the object is created, this attribute MUST be set to the value of
the name
property in the
dictionary, or an empty string if that property
wasn't set. A user agent MAY impose limits on the maximum size of the GeofenceRegionInit
name
attribute. If this limit is exceeded the constructor MUST
throw a RangeError
. If a user agent imposes a limit on the size of the name
attribute, this limit SHOULD allow for at least 100 characters.
CircularGeofenceRegion
interface
[Exposed=(Window,Worker)]
interface GeolocationPoint {
attribute double latitude;
attribute double longitude;
};
dictionary CircularGeofenceRegionInit {
double latitude;
double longitude;
double radius;
};
[Constructor(CircularGeofenceRegionInit), Exposed=(Window,Worker)]
interface CircularGeofenceRegion : GeofenceRegion
{
readonly attribute GeolocationPoint
center;
readonly attribute double radius;
};
The center
attribute MUST
return the value it was initialized to. When the object is created, this attribute MUST
be set to a
instance with its GeolocationPoint
latitude
and longitude
properties set to the same values as those properties in the
dictionary. This represents the center of
the circular region. Latitude must be between -90 and 90 inclusive. Longitude must be
between -180 and 180 inclusive. If either of these properties is outside these ranges,
the constructor will throw a CircularGeofenceRegionInit
RangeError
.
The radius
attribute MUST
return the value it was initialized to. When the object is created, this attribute MUST
be set to the value of the radius
property in the
dictionary. This represents the radius of
the circular region in meters.
CircularGeofenceRegionInit
The latitude
property of a
dictionary represents the latitude in circular
degrees of a point.
GeolocationPoint
The longitude
property of a
dictionary represents the longitude in circular
degrees of a point.
GeolocationPoint
The downside of doing error checks in the CircularGeofenceRegion constructor is that they will be actual exceptions instead of promise rejections when calling add. Would it make sense to move the validity checks to add?
The Service Worker specification defines a ServiceWorkerGlobalScope
interface, which
this specification extends.
partial interface ServiceWorkerGlobalScope {
attribute EventHandler ongeofenceenter;
attribute EventHandler ongeofenceleave;
attribute EventHandler ongeofenceerror;
};
The ongeofenceenter
attribute is
an event handler whose corresponding event handler event type is
geofenceenter
.
The ongeofenceleave
attribute is
an event handler whose corresponding event handler event type is
geofenceleave
.
The ongeofenceerror
attribute is
an event handler whose corresponding event handler event type is
geofenceerror
.
geofenceenter
and geofenceleave
events
The
interface represents a geofence being
breached.
GeofenceEvent
[Exposed=ServiceWorker]
interface GeofenceEvent : ExtendableEvent
{
readonly attribute Geofence
geofence;
readonly attribute Position
? position;
};
Upon detecting a breach of a geofence, the user agent MUST run the following steps to fire a geofence event:
ServiceWorkerGlobalScope
of the
Service Worker associated with the webapp.
GeofenceEvent
, whose
geofence
attribute is a new Geofence
instance
representing the geofence that was breached.
includePosition
attribute is true, set
event.position to the current geographical position.
geofenceenter
or
geofenceleave
, corresponding to the type of breach
event being processed.
The user agent MAY wait with firing a geofence event until some time has passed after the breach was detected, or until the for some time or distance after detecting a breach of a monitored geofence before firing an event to make sure that the geofence really was breached.
[Exposed=ServiceWorker]
interface GeofenceErrorEvent : ExtendableEvent
{
readonly attribute Geofence
geofence;
readonly attribute unsigned short code;
readonly attribute DOMString message;
};
This needs more work. I'm really not sure what attributes make sense to expose here. Also I'm not sure if is desirable/okay for all errors to be fatal/cause the geofence to be unmonitored.
Upon detecting some situation in which the user agent won't be able to detect future breached of a geofence, the user agent MUST run the following steps:
ServiceWorkerGlobalScope
of the
Service Worker associated with the webapp.
GeofenceErrorEvent
, whose
geofence
attribute is a new Geofence
instance representing
the geofence for which an error was detected.
geofenceerror
at scope.