Modern API (Recommended)
Simple functional API with direct calls and minimal abstractions
The Modern API provides a straightforward approach to geolocation with direct function calls and a single hook for continuous tracking.
Design Philosophy
Simple and Direct:
- Direct function calls: No complex abstractions or classes
- Single hook: Only
useWatchPositionfor continuous tracking - No Provider required: Just call functions directly
- Automatic cleanup: Hook handles subscription lifecycle
Core Principles:
- Simple configuration: Call
setConfiguration()once at app startup - Direct function calls: Use
getCurrentPosition(),requestPermission()etc. - One hook for tracking:
useWatchPositionfor continuous updates - Type-safe: Full TypeScript support
- Battery efficient: Native subscriptions stop immediately when disabled
Configuration
Set global configuration once at app startup.
setConfiguration()
Options:
autoRequestPermission?: boolean- Deprecated compatibility option.setConfiguration()does not request permission; callrequestPermission()explicitly when the app is ready to show the native prompt.authorizationLevel?: 'whenInUse' | 'always' | 'auto'- iOS: Authorization levelenableBackgroundLocationUpdates?: boolean- iOS: Enable background locationlocationProvider?: 'playServices' | 'android' | 'auto'- Android: Location provider.autocurrently uses Android's platformLocationManager; setplayServicesexplicitly to use Google Play Services fused location.
Type:
When to call:
- Once at app startup (e.g., in
App.tsxorindex.js) - Before making any location requests
Web behavior:
- Browser builds resolve the root import to a web entry that uses
navigator.geolocation. setConfiguration()is a no-op on web. Browser permission prompts are driven bygetCurrentPosition()/watchPosition(), not by a standalone platform request API.authorizationLevel,enableBackgroundLocationUpdates, andlocationProviderare ignored on web.
Permission Functions
checkPermission()
Check current location permission status without requesting it.
Returns: Promise<PermissionStatus>
Permission Status:
'granted'- User granted location permission'denied'- User denied permission'restricted'- Permission restricted (iOS parental controls)'undetermined'- Permission not yet requested
requestPermission()
Request location permission from the user.
Returns: Promise<PermissionStatus>
Behavior:
- Shows system permission dialog if
undetermined - Returns immediately if already
grantedordenied - On iOS, uses
authorizationLevelfrom configuration - On web, triggers the browser prompt by making a one-shot
navigator.geolocation.getCurrentPosition()call, then returns the mapped browser permission state.
Location Functions
Android Provider and Settings
Available since v1.2.
Use these helpers before user-facing precise-location flows where the app needs to know whether Android device settings can satisfy the request.
Functions:
hasServicesEnabled(): Promise<boolean>- Checks whether device-level location services are enabled.getProviderStatus(): Promise<LocationProviderStatus>- Returns provider state such aslocationServicesEnabled,gpsAvailable,networkAvailable,passiveAvailable, and Android Google Location Accuracy when Google Play Services exposes it.getLocationAvailability(): Promise<{ available: boolean; reason?: string }>- Available sincev1.2. Android reads Fused Location availability whenlocationProvider: 'playServices'is configured and otherwise falls back to platform provider/service checks. iOS maps Core Location service and authorization state.requestLocationSettings(options?): Promise<LocationProviderStatus>- Checks the requested Android location settings and shows Android's native resolution dialog when available. It resolves with the updated provider status after the settings satisfy the request.
requestLocationSettings() is Android-focused. On iOS it resolves with the
current Core Location service status and does not show a settings dialog.
Android Reliability Notes
locationProvider: 'playServices'uses Google Play Services fused location.locationProvider: 'auto'currently uses Android's platformLocationManager; setplayServicesexplicitly when you need fused behavior.- Approximate/coarse location flows are supported through permissions and
Android
granularity. - Use
getLastKnownPosition()when you want an explicit cached read without starting a fresh native request. - Modern API errors include
PLAY_SERVICE_NOT_AVAILABLE,SETTINGS_NOT_SATISFIED, andTIMEOUT.
Web Notes
Modern API web support uses the browser standard navigator.geolocation API.
It requires a secure context (https://, localhost, or another browser-trusted
origin). Unsupported browsers or unavailable providers reject location requests
with POSITION_UNAVAILABLE.
Supported on web:
checkPermission()mapsnavigator.permissions.query({ name: 'geolocation' })togranted,denied, orundeterminedwhen the Permissions API is available.requestPermission()performs a one-shot browser geolocation request because browsers do not expose a standalone geolocation permission request API.getCurrentPosition()wrapsnavigator.geolocation.getCurrentPosition().watchPosition()wrapsnavigator.geolocation.watchPosition()and returns a string token.unwatch()andstopObserving()clear browser watch IDs.
Web option behavior:
enableHighAccuracy,timeout, andmaximumAgeare forwarded to the browser.distanceFilteris applied in JavaScript for watch updates after the first emitted position.authorizationLevel,enableBackgroundLocationUpdates,locationProvider,interval,fastestInterval,useSignificantChanges, Android granularity options, and iOS tuning options are ignored because browsers do not provide matching controls.- Geocoding, heading, Android settings, and temporary full-accuracy APIs are
native-focused. On web, provider/status helpers return browser availability
where possible; unsupported sensor/geocoder calls reject with
POSITION_UNAVAILABLE.
getCurrentPosition()
Get current location (one-time request).
Parameters: options?: LocationRequestOptions
Options:
timeout?: number- Request timeout in ms (default: 600000 / 10 min)maximumAge?: number- Max age of cached location in ms (default: 0)enableHighAccuracy?: boolean- Deprecated sincev1.2. Kept for v1 compatibility only; preferaccuracy. It is expected to be removed from the Modern API in v2.accuracy?: { android?: 'high' | 'balanced' | 'low' | 'passive'; ios?: 'bestForNavigation' | 'best' | 'nearestTenMeters' | 'hundredMeters' | 'kilometer' | 'threeKilometers' | 'reduced' }- Platform-specific accuracy preset, available sincev1.2. When a preset is provided for the current platform, it takes precedence overenableHighAccuracy.granularity?: 'permission' | 'coarse' | 'fine'- Android-only request granularity, available sincev1.2.permissionfollows the granted permission level,coarseavoids fine GPS-only requests, andfinerequires fine location permission.waitForAccurateLocation?: boolean- Android-only Fused request tuning, available sincev1.2.maxUpdateAge?: number- Android-only maximum age for an initial update in ms, available sincev1.2.maxUpdateDelay?: number- Android-only maximum batching delay in ms, available sincev1.2.maxUpdates?: number- Android-only maximum watch updates before native cleanup, available sincev1.2.activityType?: 'other' | 'automotiveNavigation' | 'fitness' | 'otherNavigation' | 'airborne'- iOS Core Location activity type, available sincev1.2.pausesLocationUpdatesAutomatically?: boolean- iOS automatic pause behavior, available sincev1.2.showsBackgroundLocationIndicator?: boolean- iOS background location indicator, available sincev1.2. This only has a visible effect when the app has background location capability and permission.
Use accuracy when you need explicit platform-native behavior:
Android maps the presets to native provider/priority intent: high prefers
GPS with a network fallback, balanced uses the network provider, low uses
network/passive providers, and passive only listens through the passive
provider. iOS maps the presets to Core Location desiredAccuracy constants.
iOS tuning options are applied to both one-time requests and watches through the shared Core Location manager configuration:
Use showsBackgroundLocationIndicator only after configuring background
location in the app target, including the location background mode and the
required Info.plist location usage descriptions.
Returns: Promise<GeolocationResponse>
Response:
mocked and provider are optional metadata fields added to the Modern API response in v1.2. The /compat API keeps the @react-native-community/geolocation response shape and does not include these fields.
Error Handling:
Modern API errors use the following codes. The expanded modern-only native
setup/provider codes (INTERNAL_ERROR, PLAY_SERVICE_NOT_AVAILABLE, and
SETTINGS_NOT_SATISFIED) were added in v1.2; codes 1-3 remain aligned with the
legacy browser-style contract.
The code is committed by the native layer before a LocationError is sent to
JS. Both watchPosition error callbacks and public Promise rejections from
getCurrentPosition/requestPermission receive the same { code, message }
shape; JS only relays that object and does not parse or reclassify native
messages.
The /compat API keeps the legacy browser-style error contract with only PERMISSION_DENIED, POSITION_UNAVAILABLE, and TIMEOUT.
getLastKnownPosition()
Available since v1.2.
Read the best cached native location explicitly without starting a fresh location request. This is useful for fast app startup, stale-while-refresh UI, and cache-only flows where a fresh GPS/network request would be too expensive.
getLastKnownPosition(options?) uses the same provider and cache-filtering
options as getCurrentPosition(), but it never falls through to a fresh native
request. If no cached location satisfies maximumAge or permission is denied,
it rejects with the native LocationError contract, usually
POSITION_UNAVAILABLE or PERMISSION_DENIED.
Geocoding APIs
Available since v1.2.
Use geocode() to convert a human-readable address into candidate coordinates,
and reverseGeocode() to convert coordinates into candidate address fields.
Both APIs use the platform geocoder, so result quality, language, network
behavior, and availability can differ between Android Geocoder and iOS
CLGeocoder.
geocode(address) rejects with INTERNAL_ERROR when address is blank.
reverseGeocode(coords) rejects with INTERNAL_ERROR when latitude or
longitude is non-finite or outside the valid coordinate range. Platform
geocoder service failures reject with the same { code, message }
LocationError shape as the rest of the Modern API.
Heading APIs
Available since v1.2.
Use getHeading() for a single compass heading and watchHeading() for
continuous heading updates. Stop heading watches with the same unwatch(token)
API used by watchPosition().
Heading APIs require location permission and reject with the same
LocationError contract when permission is denied or heading sensors are not
available.
iOS Accuracy Authorization
Available since v1.2.
Use getAccuracyAuthorization() to read whether iOS currently grants full or
reduced location accuracy. Android maps fine permission to full, coarse-only
permission to reduced, and no location permission to unknown.
For iOS, requestTemporaryFullAccuracy(purposeKey) calls Core Location's
temporary full accuracy API. The purposeKey must exist in
NSLocationTemporaryUsageDescriptionDictionary in Info.plist, for example:
Passing an empty purposeKey rejects with INTERNAL_ERROR. Android does not
show a temporary accuracy prompt and resolves with the current mapped accuracy
authorization.
React Hook
useWatchPosition()
Watch for continuous location updates with automatic lifecycle management.
Options:
enabled?: boolean- Start/stop watching (default:false)enableHighAccuracy?: boolean- Deprecated sincev1.2. Kept for v1 compatibility only; preferaccuracy. It is expected to be removed from the Modern API in v2.accuracy?: { android?: 'high' | 'balanced' | 'low' | 'passive'; ios?: 'bestForNavigation' | 'best' | 'nearestTenMeters' | 'hundredMeters' | 'kilometer' | 'threeKilometers' | 'reduced' }- Platform-specific accuracy preset, available sincev1.2.granularity?: 'permission' | 'coarse' | 'fine'- Android-only request granularity, available sincev1.2waitForAccurateLocation?: boolean- Android-only high-accuracy initial update tuning, available sincev1.2maxUpdateAge?: number- Android-only maximum age for an initial update, available sincev1.2maxUpdateDelay?: number- Android-only batching delay, available sincev1.2maxUpdates?: number- Android-only watch update limit, available sincev1.2distanceFilter?: number- Minimum distance change in metersinterval?: number- Update interval in ms (Android)fastestInterval?: number- Fastest interval in ms (Android)timeout?: number- Request timeoutmaximumAge?: number- Max cached location ageuseSignificantChanges?: boolean- Use significant changes mode (iOS)activityType?: 'other' | 'automotiveNavigation' | 'fitness' | 'otherNavigation' | 'airborne'- iOS Core Location activity type, available sincev1.2pausesLocationUpdatesAutomatically?: boolean- iOS automatic pause behavior, available sincev1.2showsBackgroundLocationIndicator?: boolean- iOS background location indicator, available sincev1.2
Returns:
position: GeolocationResponse | null- Latest position (null if no update yet)error: LocationError | null- Error details if location watching failedisWatching: boolean- Whether currently watching
Key Features:
- ✅ Auto cleanup: Unsubscribes when component unmounts or
enabledbecomesfalse - ✅ Declarative: Toggle with
enabledprop - ✅ No watch ID management: Handled internally
- ✅ Battery efficient: Native subscription stops immediately when disabled
- ✅ Reactive: Changes to options restart the watch
Common Patterns:
- Toggle tracking:
- Conditional tracking (track only when screen is focused):
- Track only when permission granted:
Low-level Functions (Advanced)
For non-React code or advanced use cases, you can use the low-level watch API.
watchPosition()
Parameters:
onUpdate: (position: GeolocationResponse) => void- Success callbackonError?: (error: LocationError) => void- Error callbackoptions?: LocationRequestOptions- Location options
Returns: string - Subscription token
unwatch()
Stop a specific watch subscription.
stopObserving()
Stop ALL watch subscriptions immediately.
Advanced Patterns
Permission Check Before Location Request
Conditional Tracking Based on App State
TypeScript Support
All Modern API exports are fully typed:
ModernGeolocationConfiguration is still exported as a deprecated compatibility alias.
Type Inference
Functions and hooks provide full type inference:
Comparison with Compat API
Migration from Compat
Before (Compat API):
After (Modern API):
Benefits:
- 70% less code
- No watch ID management
- Automatic cleanup
- Declarative enable/disable
- Better TypeScript support
