# React Native Nitro Geolocation > Nitro-powered native geolocation for React Native apps ## Get started - [Choose your path](/guide/index.md): Pick the shortest React Native Nitro Geolocation 2.0 path for a new app, migration, Expo build, or background integration. - [Install and get a location](/guide/quick-start.md): Install the 2.0 with foreground-only permissions and render the first coordinates in a React Native app. - [Expo Development Builds](/guide/expo-development-build.md): react-native-nitro-geolocation requires native Nitro bindings. It does not run inside Expo Go because Expo Go cannot load arbitrary native modules that are not already bundled into the client. Use this package in Expo apps only when the app has a custom native build: Expo prebuildExpo development buildEAS build with native project generationAny custom native iOS/Android build that can install pods and Gradle modules Managed Expo apps that cannot rebuild native code should use expo-location. - [Install Doctor](/guide/install-doctor.md): nitro-geolocation doctor checks a consumer app's installation without changing any files. It has no postinstall hook and never applies native configuration automatically. Run it from the React Native app root after installing dependencies and after generating native projects: The command checks: a readable app package.json;React Native 0.75 or newer;a declared react-native-nitro-modules dependency;Android New Architecture configuration;Android coarse and fine location permissions; andthe iOS NSLocationWhenInUseUsageDescription value. Each failure includes a remediation. The process exits with status 1 when configuration errors are present and 0 when the project has only passes or warnings. Missing generated ios or android directories are warnings because an Expo prebuild or another native generation step may not have run yet. Rerun the command after generating them to complete the native checks. - [Swift Package Manager](/guide/swift-package-manager.md): React Native 0.87 adds an experimental Swift Package Manager (SwiftPM) path for iOS. react-native-nitro-geolocation supports that experiment through a precompiled package containing both Nitro Modules and Nitro Geolocation. CocoaPods remains the recommended production path while React Native marks SwiftPM experimental. - [Upgrade from 1.x to 2.0](/guide/upgrade-from-v1.md): Migrate every React Native Nitro Geolocation 2.0 breaking change with verification and rollback gates. - [Migration overview](/guide/migration-assistance.md): Use this guide when migrating an existing app from @react-native-community/geolocation, navigator.geolocation, react-native-geolocation-service, or react-native-nitro-geolocation/compat toward direct functions and hooks. - [Community Migration](/guide/community-migration.md): Use this path for apps that import @react-native-community/geolocation, navigator.geolocation, or react-native-nitro-geolocation/compat. The safest migration is two-step: switch community imports to /compat first and verify the app still behaves the same. Then refactor selected call sites where direct functions or hooks improve ownership, permission timing, cache behavior, or Android settings handling. - [Service Migration](/guide/service-migration.md): Apps that use react-native-geolocation-service should migrate directly to named imports from the package: Do not migrate through react-native-nitro-geolocation/compat. The service package exposes Android fused-provider and settings-dialog behavior that maps more closely to Nitro Geolocation's Android provider/settings API. - [2.0 Error Migration](/guide/v2-error-migration.md): React Native Nitro Geolocation 2.0 replaces the package's numeric error codes with readable string discriminants. This change does not affect /compat, which keeps the W3C-style numeric 1, 2, and 3 contract. - [2.0 Unified Background Events](/guide/v2-unified-background-events.md): React Native Nitro Geolocation 2.0 routes provider status and iOS Core Location lifecycle changes through onBackgroundEvent. Android custom notification actions also use this stream. A single subscription now observes every background event kind. On Android and iOS, each subscription receives its own initial providerChange snapshot. Later provider changes are delivered once per active subscriber. Removing a subscription removes its provider watcher as well, so a direct getProviderStatus() call can return a newer value without changing removed event counters. Web background listeners remain no-op subscriptions and do not emit an initial provider snapshot. Provider snapshots are live-only and are not stored. iOS lifecycle events are stored when the background configuration has persistence enabled, matching location, geofence, activity, HTTP sync, and Android notificationAction events. Android does not synthesize Core Location lifecycle events. Custom notification actions are Android-only; see Android setup for configuration and Headless JS delivery. - [API](/guide/api.md) - [Compatibility API (/compat)](/guide/compat-api.md) - [Watch observability](/guide/watch-observability.md): Use getActiveWatches() to inspect the watches that currently own native position or heading subscriptions: getActiveWatches() is a synchronous, point-in-time snapshot. It does not request permission, start a provider, retain callbacks, or subscribe to future changes. Entries are sorted by token and contain: token: the value accepted by unwatch().kind: position for watchPosition() or heading for watchHeading(). The snapshot covers the main package import. It does not include Compat API watches, one-shot position or heading requests, or Background Location. Android watches that finish because of maxUpdates disappear from the next snapshot automatically. Web snapshots include active browser position watches; unsupported web heading requests are not reported as active. - [GPS-only and offline verification](/guide/gps-offline-recipe.md): GPS-only routing and offline operation are related but different contracts: GPS-only result acceptance means Android's platform location manager is selected and the app accepts only a result whose provider is gps. The native high-accuracy route prefers GPS but may try the network provider when GPS cannot serve the request; the recipe detects and rejects that fallback.Offline describes the device environment. The app cannot infer that Wi-Fi and mobile data are truly unavailable from geolocation provider status, so verify it outside the app. This recipe is intentionally explicit. It does not install a hidden provider policy or retry after a timeout. It makes any native fallback visible instead of accepting it as a GPS result. - [Release readiness](/guide/release-readiness.md): Understand the 2.0 policy, declared support, tested reference stack, known limits, and ship checklist. - [Troubleshooting and support](/guide/troubleshooting.md): Diagnose install, permission, provider, foreground, and background location problems and open a useful report. - [Privacy and Compliance](/guide/privacy-compliance.md): This page describes the library's behavior and gives integrators an audit starting point. It is not legal advice. Your app determines its purposes, retention, recipients, disclosures, and lawful basis for location processing. - [DevTools Plugin (Rozenite)](/guide/devtools.md): Mock geolocation data in development with an interactive map interface using the Rozenite DevTools plugin. - [Consumer E2E contract kit](/guide/consumer-e2e-contract-kit.md): This kit gives a consuming React Native app one small product page and two black-box contracts: a granted user receives and renders a real native location;a denied user does not call the public position API and receives an actionable permission remedy. It deliberately uses the public API directly. There is no test-only provider, hidden retry, fixture branch, or library policy change. - [Why Nitro Module?](/guide/why-nitro-module.md): The Nitro Module system provides the next generation of native modules for React Native. Instead of using the bridge-based approach (JSON serialization between JS and native), Nitro Modules communicate directly through JSI (JavaScript Interface). This enables: ⚡ Direct native calls — reduced overhead🧠 Synchronous APIs for critical paths🔧 Better integration with the new Fabric renderer🧩 Cross-platform consistency and simpler maintenance In short, Nitro Geolocation builds on the proven API design of @react-native-community/geolocation while leveraging the new React Native architecture, providing a forward-compatible foundation with a migration-friendly /compat API. - [Benchmark](/guide/benchmark.md): This app benchmarks cached location read overhead between react-native-nitro-geolocation and @react-native-community/geolocation. - [Agent Context Map](/guide/agent-context-map.md): Use this map when you need code context for geolocation behavior but do not need to read generated Nitro files, full app bundles, or every scenario screen. - [React Native Directory](/guide/react-native-directory.md): Use this checklist before submitting react-native-nitro-geolocation to React Native Directory. ## Background - [Background Location overview](/background/overview.md): Decide when to use native background location, understand platform limits, and follow the shortest setup path. - [Android background setup](/background/setup-android.md): Declare only the Android permissions required by each enabled background-location feature. - [iOS background setup](/background/setup-ios.md): Configure staged iOS location access, background mode, and optional motion access with product-specific purpose text. - [Permissions](/background/permissions.md): foreground and background are separate because Android and iOS gate background access differently. needsSettingsRedirect means the app still needs a settings or app-resume round-trip before background tracking can start. On Android 11+, requestBackgroundPermission() can open the app settings screen because the platform no longer allows inline background-location prompts. On iOS, it can also remain true until Always authorization is granted; use openAppLocationSettings() after explaining why Always access is required. When the current iOS status is When In Use, the OS may keep that status without delivering another authorization callback. The request therefore returns the current result instead of waiting for a callback that may never arrive. Call checkBackgroundPermission() again from your app-resume path. - [Start and stop tracking](/background/start-stop.md): android.locationProvider uses the same public values as foreground configuration: 'auto', 'playServices', or 'android'. Use 'android' to force the platform LocationManager; the Nitro-only 'android_platform' spelling is not part of the public API. Use Activity Recognition before switching to trackingMode: 'activityAware'. Use Android Setup before enabling boot restart or changing foreground-service behavior. - [Storage Recovery](/background/storage.md): JavaScript listeners are delivery. Native storage is the source of truth. Use getStoredBackgroundEvents() for mixed event recovery. In 2.x this includes iOS lifecycle and Android notificationAction events when persistence is enabled. Custom notification actions can be selected with getStoredBackgroundEvents({ types: ['notificationAction'] }). providerChange events are live snapshots for active JavaScript subscriptions and are not written to the background store. Handle stored events idempotently using the event ID, then acknowledge them with markStoredBackgroundEventsDelivered(). A notification action can reach the live listener or Headless JS before the same event is recovered from storage. - [Android Headless JS](/background/headless-js.md): Register task at app root, outside React components: Headless JS is Android-only. On iOS, read stored events after app initialization. - [Native HTTP Sync](/background/http-sync.md): When sync is configured, native code attempts a flush after stored locations reach syncThreshold, respecting syncInterval. Failed flushes can retry up to maxRetries when retry is enabled. Call syncStoredLocations() to manually flush the native queue. Manual and automatic flushes share one serial native queue. Automatic work rechecks the active run, current sync options, threshold, batch, and interval when its turn begins, so queued work cannot reuse a stale batch or upload the same stored locations alongside a manual flush. While an automatic upload is running, further location callbacks coalesce into one latest pending check instead of growing an unbounded upload backlog. Pending work from an older run cannot replace a newer run's check. After a successful upload, native code continues one batch at a time until the unsynced count falls below syncThreshold; each batch returns to the serial queue first, so manual sync and a newer run can take precedence. Calling configureBackgroundLocation() starts a new sync-config revision. An older upload may finish, but its continuation must reapply the replacement config's syncInterval before starting another batch. With autoClear: false, successfully uploaded rows are marked synced but remain in local storage until the app clears them. Set retention and deletion limits deliberately. With autoClear: true, successfully synced rows are removed after the native store commits the sync result. - [Geofencing](/background/geofencing.md): sub.remove() detaches this JavaScript listener but leaves native monitoring in place. removeGeofences() unregisters the named native regions; call it only when the product should stop monitoring them. notifyOnDwell is Android-only. iOS region monitoring supports enter and exit. On Android, configureBackgroundLocation({ geofencing: ... }) sets defaults for initialTrigger and notificationResponsiveness (milliseconds). Fields supplied in the second argument to addGeofences(regions, options) override those defaults for that registration; an empty initialTrigger: [] disables initial triggers. Native restoration of persisted regions uses the persisted configuration defaults, so put policies that must survive process death/reboot in geofencing, not only in a per-call override. These two scheduling options are not supported by iOS. - [Activity Recognition](/background/activity-recognition.md): Calling startActivityRecognition() enables the standalone activity stream, so its options do not include enabled. Use activityRecognition.enabled only inside BackgroundLocationOptions when activity recognition is controlled by background tracking configuration. Activity events are delivered through the same native event pipeline as location and geofence events. Android uses Activity Recognition APIs. iOS uses Core Motion when available. On iOS, starting standalone or activity-aware tracking waits for the Core Motion authorization decision. It rejects when activity recognition is unavailable, denied, restricted, or still undetermined after the permission timeout; it does not report a silently inactive motion provider as running. On Android 10+, request android.permission.ACTIVITY_RECOGNITION at runtime before calling startActivityRecognition() or using trackingMode: 'activityAware'. trackingMode: 'activityAware' enables activity collection alongside background tracking. Apps can use onActivityChange events to pause, resume, or tune tracking policy for their own product rules. - [iOS Location Lifecycle](/background/location-lifecycle.md): Observe the moments when Core Location pauses or resumes background location updates: In 2.x, this convenience listener filters lifecycle events from the same native subscription used by onBackgroundEvent. It reports the native locationManagerDidPauseLocationUpdates and locationManagerDidResumeLocationUpdates delegate callbacks. iOS decides whether to pause based on the configured activity and device movement. After an automatic pause, Core Location does not restart updates just because the device moves: your app must call startBackgroundLocation() before iOS can report the resumed callback. Starting or stopping tracking does not synthesize a lifecycle event. The listener is observational: it does not restart tracking or change the background state. The event also arrives through onBackgroundEvent with type: 'lifecycle' and is retained by getStoredBackgroundEvents() when background persistence is enabled. Choose an app-specific restart policy after a pause if your use case needs one. Android and web return a removable subscription but do not emit these iOS Core Location events. Keep platform-independent cleanup code, but do not wait for a pause or resume event outside iOS. - [Background Reliability Contract](/background/reliability-contract.md): Background location is a native, best-effort pipeline. Starting it means the library has registered the platform mechanisms described below; it does not promise a fixed delivery interval while the app is backgrounded, suspended, terminated, force-stopped, or constrained by battery policy. - [Long-Run Background E2E](/background/long-run-e2e.md): The example app has two background E2E pages: background-e2e is a short smoke page for API contracts.background-long-run is a device-level page for long-running checks. The long-run page reads native storage and status. It does not pass from React state alone, so app restarts do not hide missing native delivery. - [Troubleshooting](/background/troubleshooting.md)