1. Why you should care about geolocation
Whether you’re building a ride-sharing app, a “find my charger” map, or simply pre-filling an address form, you need the device’s GPS coordinates. Capacitor gives you two main tools:
Platform | Best-practice API |
---|---|
Android & iOS | @capacitor/geolocation plugin |
Web (desktop / mobile browsers) | navigator.geolocation |
Using each one correctly—and waiting for the result before moving on—is the trick. (Capacitor)
2. The asynchronous puzzle (explained for total beginners)
JavaScript never blocks the main thread.
Both Capacitor’s plugin and the browser’s geolocation run asynchronously because the device might need a few seconds to talk to the GPS chip or the cell tower.
- Plugin method (
Geolocation.getCurrentPosition
) already returns a Promise, so you canawait
it. - Browser method (
navigator.geolocation.getCurrentPosition
) is callback-based—noawait
possible until we wrap it in our own Promise. (WhatWebCanDo)
3. Quick setup checklist
- Install the plugin
npm i @capacitor/geolocation npx cap sync
- Add permissions
- Android: In
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- iOS: In
ios/App/App/Info.plist
<key>NSLocationWhenInUseUsageDescription</key> <string>This app needs your location to show nearby chargers.</string>
- Android: In
- Enable HTTPS for web – Browsers deliver location only from secure origins.
4. Code you can copy-paste
const FALL_BACK_POSITION = { lat: 0, lng: 0 };
function browserGeolocation(
opts?: PositionOptions
): Promise<{ lat: number; lng: number }> {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
pos =>
resolve({
lat: pos.coords.latitude,
lng: pos.coords.longitude,
}),
reject,
opts
);
});
}
export async function getCurrentPosition(): Promise<{
lat: number;
lng: number;
}> {
try {
// 1. Detect platform
const platform = Capacitor.getPlatform();
// 2. Pick the best API and await it
const coords =
platform === 'web'
? await browserGeolocation({ enableHighAccuracy: true, timeout: 10_000 })
: (() => {
const { coords } = await Geolocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 10_000,
});
return { lat: coords.latitude, lng: coords.longitude };
})();
// 3. Cache for later
localStorage.setItem('coords', `${coords.lat}|${coords.lng}`);
return coords;
} catch (err) {
console.error('Location error:', err);
return FALL_BACK_POSITION;
}
}
What this does
- Single exit point – you never return before a Promise resolves.
- Graceful fallback – if the user denies permission or the GPS times out, you still get predictable coordinates.
- No duplicated code – Android and iOS share the same plugin call; only the web uses the wrapper.
5. Common issues & quick fixes
Symptom | Cause | Fix |
---|---|---|
iOS returns nothing | Missing NSLocationWhenInUseUsageDescription | Add it to Info.plist . |
Android instantly returns cached location | Old Google Play-services cache | Pass a small maximumAge or call watchPosition for fresh data. |
Browser throws “Only secure origins are allowed” | Serving over HTTP | Use HTTPS or localhost . |
Timeout despite good signal | GPS cold start | Increase timeout to 15 000 ms and keep enableHighAccuracy: true . |
6. Best practices for production
- Ask permission at a “why” moment (e.g., when the user taps “Find chargers near me”) instead of on app launch.
- Use reverse geocoding sparingly; it costs requests. Cache results keyed by lat/lng pairs.
- Respect privacy – store coordinates only as long as truly needed and disclose usage in your privacy policy.
- Provide a manual fallback – a text field or map picker for users who refuse location access.
7. Key takeaways
- Capacitor’s geolocation plugin is Promise-ready—
await
it. - The browser API isn’t, so wrap it in a Promise.
- Unified, async/await-based code keeps your UI smooth across Android, iOS, and web.
Add these snippets to your own Ionic/Capacitor project and you’ll never fight geolocation race conditions again.
FAQs
Q: Can I use the Capacitor plugin on the web, too?
A: The plugin simply re-routes to navigator.geolocation
, but it still returns a Promise, so you can avoid writing the wrapper twice. Performance is identical.
Q: How do I track movement instead of a single coordinate?
A: Use Geolocation.watchPosition
(plugin) or navigator.geolocation.watchPosition
. Remember to clearWatch
when done to save battery.
Q: Does this work in the background?
A: Not out of the box. On Android you need a foreground service; on iOS you must enable the “Location updates” background mode and use significant-change or region monitoring.
Final words
That’s it! Copy the code, tweak your permission strings, and ship location-aware features with confidence. Happy coding! 🎉