react-native-bg-geolocation is an open-source package I built to solve the hardest part of mobile location tracking: getting reliable location updates not just in the foreground, but in the background and even after the user force-quits the app. It uses only public platform APIs — FusedLocationProvider and Activity Recognition on Android, and Core Location, Core Motion, BGTaskScheduler, and the Location Push Service Extension on iOS — and exposes the same API shape as the popular react-native-background-geolocation library, so migration is straightforward.
Key takeaways
- Tracks location across foreground, background, Android headless mode, and iOS force-quit (kill-state) using OS-owned delivery mechanisms.
- Ships geofencing, motion detection, reboot persistence, iOS Live Activity, and pluggable Socket.IO → REST delivery out of the box.
- TypeScript-first, requires Always authorization for background work, and mirrors the familiar react-native-background-geolocation API.
What react-native-bg-geolocation does
Most location libraries work fine while your screen is open and quietly stop the moment the app is backgrounded or killed — which is exactly when rideshare, delivery, fitness, and fleet apps need a fix the most. This package is built around that gap. It collects location in the foreground and background, detects when the device transitions between moving and stationary, and delivers each fix to your server through a native Socket.IO connection with an automatic REST fallback, or through your own JavaScript handler.
Under the hood it leans on OS-owned delivery so updates survive a dead process: an Android FusedLocation PendingIntent delivered to a BroadcastReceiver, and iOS significant-change and region monitoring that can relaunch a terminated app. It also adds the pieces production apps actually need — geofencing with CLCircularRegion and GeofencingClient, reboot persistence, an iOS Live Activity for the Lock Screen and Dynamic Island, and an Android headless JS task for running your code after the app is killed.
Installation and platform setup
Install with npm install react-native-bg-geolocation or yarn add react-native-bg-geolocation. The package is TypeScript-first and declares react and react-native as peer dependencies, targeting iOS 15.1+ and modern Android background-tracking APIs.
On iOS, add the usage-description keys to Info.plist (NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription, NSMotionUsageDescription), declare the relevant UIBackgroundModes (location, fetch, processing, and remote-notification for the push path), register your BGTaskScheduler identifier, and register the BGTask in AppDelegate. The example app ships a complete AppDelegate.swift to copy from.
On Android, the library manifest already declares the required permissions — ACCESS_FINE_LOCATION, ACCESS_BACKGROUND_LOCATION, FOREGROUND_SERVICE_LOCATION, ACTIVITY_RECOGNITION, WAKE_LOCK, and RECEIVE_BOOT_COMPLETED — so you only need to request the runtime permissions from JavaScript. Background tracking on both platforms requires Always-level authorization, not just While-Using.
Basic usage
You configure the plugin once with a nested config object passed to ready() — the same shape as react-native-background-geolocation, with geolocation settings (desiredAccuracy, distanceFilter, stopTimeout, locationAuthorizationRequest) and app settings (stopOnTerminate, startOnBoot, enableHeadless, foregroundService, the Android notification, and Live Activity options). Then you attach listeners such as onLocation, onMotionChange, onActivityChange, onGeofence, onHeartbeat, and onHttp.
After configuring, call requestPermission(); if it returns AuthorizationStatus.Always you call start() to begin tracking, and stop() to end it. The API also covers on-demand reads (getCurrentPosition, watchPosition), an odometer, local persistence of fixes (getLocations, getCount, sync), and a full geofencing surface (addGeofence, removeGeofence, getGeofences). Enums like AuthorizationStatus, DesiredAccuracy, and LogLevel ship with the package, so the integration stays type-safe end to end.
Kill-state delivery: the hard part
Getting a location after the user swipes the app away is where most solutions break, and it works very differently on each platform. On Android, the FusedLocation PendingIntent is owned by the OS and delivered to a BroadcastReceiver even when the process is dead; a START_STICKY foreground service keeps priority high, and onTaskRemoved reschedules through AlarmManager. Those kill-state events fire a React Native Headless JS task, so you register a handler at module scope (in index.js) and your JavaScript runs to upload the fix.
On iOS, Core Location can relaunch an app the system terminated via significant-change and region events — but after an explicit force-quit, it will not. The production answer is the Location Push Service Extension: your server sends an APNs push of type 'location' to the device's location-push token, and iOS launches a tiny separate extension process — with no React Native bridge — that captures one fix and uploads it natively. Because there is no JavaScript in that process, the SDK performs delivery itself (Socket.IO first, REST fallback), reading its upload config from a shared App Group. This requires Apple's location.push entitlement (a one-time request that takes about 24–48 hours to approve) and Always authorization.
Flexible delivery and payloads
Delivery is pluggable. The native deliverer tries a Socket.IO connection first and falls back to a REST endpoint after a configurable timeout, sending your auth token in both the socket CONNECT handshake and as a REST Bearer header. You configure this once with setLocationPushConfig, including custom HTTP headers for the fallback.
Because the kill-state upload happens in native code, the package exposes a payloadTemplate so you can define the exact JSON shape your backend expects without patching native code. Template tokens such as {latitude}, {longitude}, {accuracy}, {speed}, {fcmToken}, {queryId}, and {userCurrentTime} are substituted with live values; a value that is exactly one token keeps its native type (numbers stay numbers), while inline tokens interpolate as strings, and nested objects are supported. When the app is alive it still delivers natively and additionally fires a locationpush JS event so your code can react.
When to reach for it
This package is a good fit when continuous or on-demand background location is a core product requirement — live driver or courier tracking, fleet and asset monitoring, fitness route recording, safety and check-in features, or geofence-triggered workflows. If you only need a one-off location while the app is open, the lighter community geolocation modules are simpler.
Because it mirrors the react-native-background-geolocation API surface (AuthorizationStatus, DesiredAccuracy, nested Config, and the same event names), teams already familiar with that library can adopt it with minimal changes. It is MIT-licensed and open source, so you can read exactly how each platform path works and adapt it to your own backend.