Geolocation API: accessing the user's location
In one line: navigator.geolocation gives you the user’s physical position
(latitude, longitude, and optional altitude/accuracy) after the browser obtains
explicit permission — access is always user-initiated and gated by a permission prompt
that the page cannot bypass.
Requesting position
Section titled “Requesting position”One-shot: getCurrentPosition
Section titled “One-shot: getCurrentPosition”navigator.geolocation.getCurrentPosition( (position) => { const { latitude, longitude, accuracy } = position.coords; console.log(`${latitude}, ${longitude} (±${accuracy}m)`); }, (error) => { // error.code: 1=PERMISSION_DENIED, 2=POSITION_UNAVAILABLE, 3=TIMEOUT console.error(`Geolocation error ${error.code}: ${error.message}`); }, { enableHighAccuracy: false, // GPS vs network-based; battery trade-off timeout: 10_000, // ms before the error callback fires maximumAge: 60_000, // accept a cached position up to 60 s old });Continuous: watchPosition
Section titled “Continuous: watchPosition”watchPosition returns a watch ID and fires the success callback each time the
position changes. Call clearWatch(id) to stop tracking:
const watchId = navigator.geolocation.watchPosition( (pos) => updateMap(pos.coords), (err) => handleError(err));
// Later, when tracking is no longer needed:navigator.geolocation.clearWatch(watchId);The permission model
Section titled “The permission model”Geolocation access is always gated by an explicit browser permission prompt. The
browser asks the user “Allow [site] to know your location?” the first time
getCurrentPosition or watchPosition is called. The spec requires that this prompt
cannot be suppressed, pre-answered, or invoked without a browsing context.
- The user can choose Allow, Block, or (in some browsers) Allow once.
- A blocked grant surfaces in the error callback as
error.code === 1(PERMISSION_DENIED). Your code must handle this gracefully — show a manual location-entry fallback or a contextual explanation. - You can query the current permission state without prompting via the Permissions
API:
navigator.permissions.query({ name: 'geolocation' })resolves to{ state: 'granted' | 'denied' | 'prompt' }.
Secure context (HTTPS)
Section titled “Secure context (HTTPS)”Geolocation is only available in secure contexts — HTTPS or localhost. On plain
HTTP, navigator.geolocation is undefined regardless of browser.
No user-gesture requirement (but prompt is still shown)
Section titled “No user-gesture requirement (but prompt is still shown)”Unlike some APIs, calling getCurrentPosition does not require an active user gesture.
However, the browser will display the permission prompt, and users who were not expecting
it will often deny it. For the best grant rate, call geolocation only when the user has
clearly requested location-based functionality (e.g., by clicking a “Use my location”
button).
enableHighAccuracy and battery
Section titled “enableHighAccuracy and battery”Setting enableHighAccuracy: true requests GPS-quality position. This drains the
battery faster and takes longer on cold start. Only set it when sub-50-meter accuracy is
genuinely required (turn-by-turn navigation). For “near me” lookups, the default
(false) network-based position is usually precise enough.
Privacy considerations
Section titled “Privacy considerations”- Never store raw coordinates beyond the task that required them.
- Disclose location use clearly before triggering the prompt — users grant at higher rates when they understand why.
- Prefer coarse location (
enableHighAccuracy: false) unless precision is essential.
Browser & ecosystem support
Section titled “Browser & ecosystem support”See /compatibility/ for current per-browser data.
Decision framework
Section titled “Decision framework”| Decision question | Recommended action | Rationale |
|---|---|---|
| One-time position lookup? | getCurrentPosition with reasonable timeout and maximumAge. |
Avoids continuous tracking drain; maximumAge returns a recent cached fix instantly. |
| Real-time position tracking (map, navigation)? | watchPosition + clearWatch when done. |
Keeps the fix current; always stop watching when the feature is not active. |
| Need to check permission state without prompting? | navigator.permissions.query({ name: 'geolocation' }). |
Allows conditional UI without triggering an unexpected prompt. |
| User denied — what now? | Show a manual address/city input; explain why location is useful. | PERMISSION_DENIED is permanent until the user manually resets it in browser settings. |
| Accuracy vs battery trade-off? | Default to enableHighAccuracy: false; only set true for navigation. |
GPS accuracy rarely justifies the battery cost for “near me” features. |
Practical checklist
Section titled “Practical checklist”- Serve the page over HTTPS — Geolocation is unavailable on plain HTTP.
- Call
getCurrentPosition/watchPositiononly when the user has clearly opted in to location functionality. - Handle all three error codes:
PERMISSION_DENIED(1),POSITION_UNAVAILABLE(2),TIMEOUT(3). - Provide a non-location fallback (e.g., manual address input) for denied or unavailable cases.
- Set a
timeoutand a sensiblemaximumAgeon every call. - Always call
clearWatch()when continuous tracking is no longer needed to avoid battery drain. - Query permission state first with the Permissions API if you want to conditionally show or hide a location feature.