Geolocation Api
The Geolocation API was standardized in 2008, uses callbacks instead of promises, and gives you exactly five properties from each location fix. Here is everything the API does.
Here is the thing about the Geolocation API: it predates promises.
Every other modern web API uses promises. This one was standardized in 2008 and stayed that way. You adapt to it rather than the other way around -- callbacks, error callbacks, and an options object, all in a row.
It is also one of the simplest APIs on the platform once you see the shape of it. Two methods, five useful properties on the position object, three options.
If you want to understand how the browser actually finds you before diving into the API, that post covers the GPS vs Wi-Fi scanning difference and why coords.accuracy is the most useful property the API returns.
Feature Detection
The Geolocation API is green tier -- it works in every major browser on every platform, including iOS Safari. Feature detection is still good practice, particularly to give older browsers a clean failure path:
if ('geolocation' in navigator) {
// safe to call the API
} else {
showNotSupportedMessage();
}Getting the Location Once
getCurrentPosition fires your success callback once and stops.
navigator.geolocation.getCurrentPosition(
position => {
const { latitude, longitude, accuracy } = position.coords;
console.log(`${latitude}, ${longitude} (±${accuracy}m)`);
},
error => {
if (error.code === error.PERMISSION_DENIED) {
showSettingsInstructions();
} else if (error.code === error.TIMEOUT) {
showRetryUI();
}
},
{
timeout: 8000,
maximumAge: 30000,
enableHighAccuracy: false
}
);The first argument is the success callback. The second is the error callback. The third is an options object.
Watching the Position Continuously
watchPosition uses the exact same API signature, but fires your callback repeatedly as the user moves.
const watchId = navigator.geolocation.watchPosition(
position => updateMapPin(position.coords),
error => console.error(error.code)
);
// Stop watching when no longer needed
navigator.geolocation.clearWatch(watchId);Call clearWatch() when you're done. Leaving a watch running when the user navigates away from the map feature wastes battery and battery permission. Always pair every watchPosition with a clearWatch.
ExpandThe Geolocation API: methods, position object, options, and error codes
What the Position Object Contains
position.timestamp // epoch ms when the fix was acquired
position.coords.latitude // decimal degrees, always present
position.coords.longitude // decimal degrees, always present
position.coords.accuracy // radius in meters -- always present
position.coords.altitude // meters above sea level, or null
position.coords.altitudeAccuracy // null if altitude is null
position.coords.heading // degrees from north, or null
position.coords.speed // m/s, or nullThe three that are always populated: latitude, longitude, and accuracy. Everything else may be null.
Null values are diagnostic. altitude being null means the fix came from Wi-Fi scanning, not GPS. heading and speed being null means the device isn't moving fast enough to calculate them, or isn't using GPS. accuracy of 16 meters is consistent with Wi-Fi. accuracy of 600 is consistent with a desktop computer using IP address as a fallback.
The Three Options
timeout -- milliseconds to wait before calling the error callback with TIMEOUT. Default is Infinity, which means wait as long as necessary. Setting this to 8000 gives the user 8 seconds before you show a "couldn't get location" message.
maximumAge -- how old a cached location is acceptable, in milliseconds. Default is 0, meaning "give me a fresh fix right now." If you set this to 60000, the browser will return any fix acquired in the last minute without requesting a new one. For most use cases -- "show me nearby cafes" -- a 30-second-old location is perfectly fine, and accepting cached data makes the response noticeably faster.
enableHighAccuracy -- a boolean hint that the device should prefer GPS over Wi-Fi. This is a hint, not a guarantee. Setting it to true increases battery usage and slows the initial response. Use it only when you genuinely need 10-meter precision rather than 50-meter.
One edge case specific to iOS is worth its own post: when a user chooses "approximate" location instead of "precise," Safari's handling of that choice affects every website they visit -- not just yours.
HTTPS and Localhost
The Geolocation API requires a secure context. If you're not on HTTPS, the permission dialog will not appear and the API will error.
The localhost exception applies -- http://localhost works for development. One edge case: http://127.0.0.1 does not count. It has to be the literal hostname localhost, not the IP address. If your local dev server serves to an IP address, add a localhost alias or use HTTPS locally.
Testing with Chrome DevTools
Chrome has a sensor override panel hidden in the DevTools drawer. Open DevTools, click the three-dot menu, choose "More tools" then "Sensors." Under Location, you can set any coordinates you want.
DevTools → three-dot menu → More tools → Sensors → LocationSwitch the dropdown from "No override" to a preset city, or enter custom latitude and longitude. Any active getCurrentPosition or watchPosition call will immediately return the overridden location.
This is the practical way to test your app against specific coordinates without physically traveling. If you have a watchPosition running, you can also switch between locations while watching -- your app's position tracking will update in real time.
For more complex testing -- replaying a real GPS track -- there are Chrome extensions that accept a .gpx file (the standard format for recorded GPS routes) and replay your walk through the sensor emulator.
The Essentials
getCurrentPositionfires once.watchPositionfires continuously. Both take identical arguments.- Always call
clearWatch()when done -- leaving a watch running wastes battery. coords.accuracyin meters is the most useful diagnostic. ~10m suggests GPS. 50m+ suggests Wi-Fi scanning.nullaltitude confirms Wi-Fi.maximumAgeaccepts cached locations -- set it to 30-60 seconds for most use cases to get faster responses.- Requires HTTPS.
http://localhostworks for development.http://127.0.0.1does not.
Further Reading and Watching
- Using the Geolocation API -- JavaScript Tutorial (YouTube) -- clean walkthrough of
getCurrentPositionandwatchPositionwith a live map example - Geolocation API -- web.dev -- best practices for prompting timing, accuracy options, and handling errors gracefully
Keep reading