Skip to content

Capabilities · API

Geolocation API

Published

Widely available since 2015-07W3C

navigator.geolocation reports the device’s position (latitude, longitude, accuracy radius, and optional altitude, heading, and speed) through a one-shot getCurrentPosition() or a continuous watchPosition(), after the browser has shown its own permission prompt. Nothing is returned synchronously: results and failures arrive in the callbacks you pass.

Every engine has shipped it since Chrome 5, Firefox 3.5, and Safari 5 (iOS 3). The secure-context requirement arrived later: Chrome 50, Firefox 55, and Safari 10 reject requests from http:// origins other than localhost with PERMISSION_DENIED while still exposing navigator.geolocation (BCD api.Geolocation.secure_context_required). GeolocationCoordinates.toJSON() is newer still: Chrome 126, Firefox 129, Safari 18.

navigator.geolocation.getCurrentPosition(successCallback)
navigator.geolocation.getCurrentPosition(successCallback, errorCallback)
navigator.geolocation.getCurrentPosition(successCallback, errorCallback, options)
navigator.geolocation.watchPosition(successCallback)
navigator.geolocation.watchPosition(successCallback, errorCallback)
navigator.geolocation.watchPosition(successCallback, errorCallback, options)
navigator.geolocation.clearWatch(watchId)

getCurrentPosition() returns undefined. watchPosition() returns a long watch id greater than zero, invokes successCallback each time the position changes until clearWatch(watchId) is called, and returns 0 when the document is not fully active. No user activation is required, but Chrome logs a [Violation] when the first request is not inside one (see the observed callout).

The two request methods share three parameters.

Parameter Type Required Description
successCallback PositionCallback Yes Receives a GeolocationPosition with coords (a GeolocationCoordinates) and timestamp (an EpochTimeStamp).
errorCallback PositionErrorCallback? No Receives a GeolocationPositionError with code and message. Without it, failures are silent.
options PositionOptions No The dictionary below.

PositionOptions has three members, all optional.

Member Type Required Description
enableHighAccuracy boolean No Default false. A hint to use the most accurate source available (GPS on phones), at the cost of slower first fix and more battery. A cached position is reused only when its [[isHighAccuracy]] flag matches this value.
timeout [Clamp] unsigned long No Default 0xFFFFFFFF ms. Maximum time to wait once acquisition starts; time spent waiting for the permission prompt or for a hidden document to become visible does not count. 0 can fail immediately.
maximumAge [Clamp] unsigned long No Default 0. Accept a cached position no older than this many milliseconds; 0 forces a fresh fix.

Neither method throws. Failures reach errorCallback as a GeolocationPositionError whose code is one of three constants on the interface.

code Constant Condition
1 PERMISSION_DENIED The user or system denied the permission; the document is not allowed to use the geolocation Permissions Policy feature; or the environment is a non-secure context.
2 POSITION_UNAVAILABLE The document is not fully active; or the underlying system failed to acquire a position.
3 TIMEOUT options.timeout elapsed after acquisition started.

message is implementation-defined text for developers, not for display. Chrome reports permission failures with User denied Geolocation and Permissions Policy failures with Geolocation has been disabled in this document by permissions policy. A PERMISSION_DENIED from the user persists until they change the setting themselves; repeated calls do not re-prompt.

Each example checks "geolocation" in navigator and gives the user a manual way to supply a location when the API is missing or the request fails. Triggering the request from a button keeps the prompt expected and avoids Chrome’s violation warning.

A one-shot fix with a manual address fallback

Section titled “A one-shot fix with a manual address fallback”

A timeout and a non-zero maximumAge keep the request from hanging on devices with no fix available. Every error code lands in the same fallback: showing the address field.

const addressField = document.querySelector("#address");
function useManualEntry(reason) {
addressField.hidden = false;
addressField.placeholder = reason;
}
document.querySelector("#use-location").addEventListener("click", () => {
if (!("geolocation" in navigator)) {
useManualEntry("Enter your city");
return;
}
navigator.geolocation.getCurrentPosition(
({ coords }) => {
showNearby(coords.latitude, coords.longitude, coords.accuracy);
},
(error) => {
const reasons = { 1: "Location access denied", 2: "Location unavailable", 3: "Location timed out" };
useManualEntry(reasons[error.code] ?? error.message);
},
{ enableHighAccuracy: false, timeout: 10_000, maximumAge: 60_000 },
);
});

coords.accuracy is the 95 % confidence radius in metres; a “near me” feature can treat anything under a few hundred metres as good enough without enableHighAccuracy.

Tracking a route and stopping when the view closes

Section titled “Tracking a route and stopping when the view closes”

watchPosition() keeps the radio on until clearWatch() runs, so tie the watch to the lifetime of the UI that needs it.

let watchId = null;
function startTracking(onMove) {
if (!("geolocation" in navigator)) return false;
watchId = navigator.geolocation.watchPosition(
(position) => onMove(position.coords),
(error) => {
stopTracking();
console.warn(`Tracking stopped: ${error.code} ${error.message}`);
},
{ enableHighAccuracy: true, maximumAge: 0 },
);
return watchId !== 0;
}
function stopTracking() {
if (watchId !== null) navigator.geolocation.clearWatch(watchId);
watchId = null;
}
document.querySelector("#start").addEventListener("click", () => startTracking(updateMap));
document.querySelector("#stop").addEventListener("click", stopTracking);
window.addEventListener("pagehide", stopTracking);

A 0 return value means the document was not fully active when the watch was requested, so the function reports failure instead of waiting for an error callback that may not come.

Checking the permission state before prompting

Section titled “Checking the permission state before prompting”

navigator.permissions.query({ name: "geolocation" }) reads the state without triggering a prompt, which lets the page show a “Use my location” button only when it can succeed or explain how to re-enable a denied permission.

async function locationButtonState() {
if (!("geolocation" in navigator)) return "unsupported";
if (!navigator.permissions) return "unknown"; // request on click and handle the error
const { state } = await navigator.permissions.query({ name: "geolocation" });
return state; // "granted" | "prompt" | "denied"
}
const state = await locationButtonState();
document.querySelector("#use-location").hidden = state === "unsupported" || state === "denied";
document.querySelector("#denied-help").hidden = state !== "denied";

The "unknown" branch matters for older WebViews that have geolocation but not navigator.permissions; there the page falls back to requesting on click and reading the error code.

Specifications

SpecificationStatus
Geolocation APIW3C
Geolocation API: getCurrentPosition() methodW3C
Geolocation API: watchPosition() methodW3C
Geolocation API: PositionOptions dictionaryW3C
  • Legend
  • Yes
  • Partial
  • Flag
  • No
  • Unknown
Browser / PlatformSupportVersionsConfidenceSourceNotes
Chrome (Desktop)Yes5highsource—
Chrome (Android)Yes18highsource1
Edge (Desktop)Yes12highsource—
Firefox (Desktop)Yes3.5highsource2
Firefox (Android)Yes4highsource—
Safari (macOS)Yes5highsource—
Safari (iOS)Yes3highsource3
Samsung InternetYes1.0highsource4
WebView (Android)Yes4.4highsource5
  1. Derived by browser-compat-data mirroring from Chrome.
  2. GPSD (https://gpsd.gitlab.io/gpsd/index.html) (GPS daemon) support added in Firefox 3.6. WiFi-based location is provided by Google (privacy (https://support.mozilla.org/en-US/kb/does-firefox-share-my-location-websites)) or a custom provider (MLS instructions (https://wiki.mozilla.org/CloudServices/Location/Software)).
  3. browser-compat-data records support as ≤3: present in the earliest Safari on iOS release it tracks.
  4. Derived by browser-compat-data mirroring from Chrome Android.
  5. Derived by browser-compat-data mirroring from Chrome Android.

Source data: /compatibility/geolocation.json · Global usage: 93 % (StatCounter 2026-05)

Source: spec · MDN · Last verified 2026-10-03 · Confidence: high (computed from sources)