@gabriel-sisjr/react-native-background-location
v0.12.0
Published
React Native library for background location tracking using TurboModules. Track user location even when the app is minimized or in the background.
Maintainers
Keywords
Readme
@gabriel-sisjr/react-native-background-location
A cross-platform React Native library for background location tracking built on TurboModules (New Architecture). Tracks user location reliably on both Android and iOS even when the app is minimized, with persistent storage, crash recovery, and platform-native behavior.
![]()
Table of Contents
- Features
- Installation
- Quick Start
- Hooks
- API Reference
- Types
- Enums
- Notification Customization
- Documentation
- Platform Support
- Contributing
- License
Features
- Cross-platform background location tracking (Android and iOS)
- Real-time event-driven location updates on both platforms
- Crash recovery with automatic session restoration (WorkManager on Android, significant location monitoring on iOS)
- Configurable accuracy levels and update intervals for battery efficiency
- Distance filtering and callback throttling
- Session-based tracking organized by trip IDs
- Persistent storage: Room Database (Android) / Core Data (iOS)
- Full notification customization on Android: icons, colors, action buttons, dynamic updates
- Static notification defaults via AndroidManifest or convention drawables (Android)
- Android 14/15 compliance (foreground service type, timeout handling)
- Provider abstraction with Google Play Services primary and fallback provider (Android)
- CLLocationManager with WhenInUse and Always authorization levels (iOS)
- Foreground-only mode (no background permission required)
- Fully typed TypeScript API with unified cross-platform hooks
Installation
npm install @gabriel-sisjr/react-native-background-location
# or
yarn add @gabriel-sisjr/react-native-background-locationAndroid Setup
Add the required permissions to android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
</manifest>On Android 11+, background location must be requested separately from foreground permissions. See the Quick Start Guide for the full permission flow and the Integration Guide for detailed setup in existing apps.
iOS Setup
- Add the following keys to your
Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to track your trips.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need your location in the background to continue tracking your trips.</string>Enable the Location updates Background Mode in your Xcode project under Signing & Capabilities.
Run
pod installin yourios/directory.
iOS: Unlike Android, iOS does not use a foreground notification for background tracking. Instead, the system shows a blue status bar indicator when the app is using location in the background. See the iOS Setup Guide for full details and App Store compliance requirements.
Quick Start
import {
useLocationPermissions,
useBackgroundLocation,
useLocationUpdates,
LocationAccuracy,
} from '@gabriel-sisjr/react-native-background-location';
function TrackingScreen() {
const { permissionStatus, requestPermissions } = useLocationPermissions();
const { startTracking, stopTracking, isTracking } = useBackgroundLocation();
const { locations, lastLocation } = useLocationUpdates({
onLocationUpdate: (loc) => console.log('New:', loc.latitude, loc.longitude),
});
if (!permissionStatus.hasAllPermissions) {
return <Button title="Grant Permissions" onPress={requestPermissions} />;
}
return (
<View>
<Text>Status: {isTracking ? 'Tracking' : 'Stopped'}</Text>
<Text>Points: {locations.length}</Text>
{lastLocation && <Text>Last: {lastLocation.latitude}, {lastLocation.longitude}</Text>}
<Button
title={isTracking ? 'Stop' : 'Start'}
onPress={() => isTracking
? stopTracking()
: startTracking(undefined, { accuracy: LocationAccuracy.HIGH_ACCURACY })
}
/>
</View>
);
}For step-by-step setup, see the Quick Start Guide. For the direct (non-hook) API, see Using Direct API.
Hooks
| Hook | Purpose |
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| useLocationPermissions | Manages cross-platform permission flow (Android: foreground, background, notifications; iOS: WhenInUse, Always, notifications) |
| useBackgroundLocation | Full tracking control: start, stop, locations, trip management |
| useLocationTracking | Lightweight tracking status monitor (read-only) |
| useLocationUpdates | Real-time event-driven location stream with warnings and action callbacks |
See the Hooks Guide for complete documentation, options, and examples.
API Reference
Methods
| Method | Signature | Description |
| -------------------- | ----------------------------------------------------------------- | ---------------------------------------------------- |
| startTracking | (options?: TrackingOptions) => Promise<string> | Start tracking (auto-generates trip ID) |
| startTracking | (tripId?: string, options?: TrackingOptions) => Promise<string> | Start or resume tracking with a specific trip ID |
| stopTracking | () => Promise<void> | Stop tracking and terminate the background service |
| isTracking | () => Promise<TrackingStatus> | Check if tracking is active |
| getLocations | (tripId: string) => Promise<Coords[]> | Retrieve all stored locations for a trip |
| clearTrip | (tripId: string) => Promise<void> | Delete all stored data for a trip |
| updateNotification | (title: string, text: string) => Promise<void> | Update notification content while tracking is active |
TrackingOptions
All fields are optional. Defaults are applied when omitted.
| Field | Type | Default | Description |
| ------------------------- | --------------------- | --------------- | ------------------------------------------------------------------------------------------------------- |
| updateInterval | number | 5000 | Interval between location updates (ms) |
| fastestInterval | number | 3000 | Fastest allowed update interval (ms) |
| maxWaitTime | number | 10000 | Max wait before delivering batched updates (ms) |
| accuracy | LocationAccuracy | HIGH_ACCURACY | Location accuracy priority |
| waitForAccurateLocation | boolean | false | Delay updates until accurate location is available |
| distanceFilter | number | 0 | Minimum distance (meters) between updates. 0 = no filter |
| foregroundOnly | boolean | false | Track only while app is visible (no background permission needed) |
| onUpdateInterval | number | undefined | Throttle callback execution (ms). Locations still collected at updateInterval |
| notificationOptions | NotificationOptions | see below | Notification configuration for the foreground service. See NotificationOptions. |
NotificationOptions
All fields are optional. These configure the Android foreground service notification. On iOS, notification fields are silently ignored.
| Field | Type | Default | Description |
| --------------- | ---------------------- | ---------------------------------------- | ---------------------------------------------------- |
| title | string | "Location Tracking" | Notification title |
| text | string | "Tracking your location in background" | Notification body text |
| channelName | string | "Background Location" | Android notification channel name |
| channelId | string | "background_location_channel" | Custom notification channel ID |
| priority | NotificationPriority | LOW | Notification priority |
| smallIcon | string | system default | Drawable resource name for small icon |
| largeIcon | string | undefined | Drawable resource name for large icon |
| color | string | undefined | Hex color for notification accent (e.g. "#FF5722") |
| showTimestamp | boolean | false | Show timestamp on notification |
| subtext | string | undefined | Subtext below notification content |
| actions | NotificationAction[] | undefined | Up to 3 action buttons on the notification |
Types
Coords
interface Coords {
latitude: string;
longitude: string;
timestamp: number;
accuracy?: number;
altitude?: number;
speed?: number;
bearing?: number;
verticalAccuracyMeters?: number;
speedAccuracyMetersPerSecond?: number;
bearingAccuracyDegrees?: number;
elapsedRealtimeNanos?: number;
provider?: string;
isFromMockProvider?: boolean;
}Note:
latitudeandlongitudeare strings to preserve full decimal precision. Parse withparseFloat()when using with map libraries.
TrackingStatus
interface TrackingStatus {
active: boolean;
tripId?: string;
}LocationUpdateEvent
interface LocationUpdateEvent {
tripId: string;
latitude: string;
longitude: string;
timestamp: number;
accuracy?: number;
altitude?: number;
speed?: number;
bearing?: number;
verticalAccuracyMeters?: number;
speedAccuracyMetersPerSecond?: number;
bearingAccuracyDegrees?: number;
elapsedRealtimeNanos?: number;
provider?: string;
isFromMockProvider?: boolean;
}LocationWarningEvent and LocationWarningType
type LocationWarningType =
| 'SERVICE_TIMEOUT'
| 'TASK_REMOVED'
| 'LOCATION_UNAVAILABLE';
interface LocationWarningEvent {
tripId: string;
type: LocationWarningType;
message: string;
timestamp: number;
}NotificationAction and NotificationActionEvent
interface NotificationAction {
id: string;
label: string;
}
interface NotificationActionEvent {
tripId: string;
actionId: string;
}LocationPermissionState
interface LocationPermissionState {
hasPermission: boolean;
status: LocationPermissionStatus;
canRequestAgain: boolean;
}NotificationPermissionState
interface NotificationPermissionState {
hasPermission: boolean;
status: NotificationPermissionStatus;
canRequestAgain: boolean;
}PermissionState
interface PermissionState {
hasAllPermissions: boolean;
location: LocationPermissionState;
notification: NotificationPermissionState;
}hasAllPermissions is true only when both location and notification permissions are granted. Individual permission states are accessible via the location and notification sub-objects.
UseLocationPermissionsResult
interface UseLocationPermissionsResult {
permissionStatus: PermissionState;
requestPermissions: () => Promise<boolean>;
checkPermissions: () => Promise<boolean>;
isRequesting: boolean;
}UseBackgroundLocationResult
interface UseBackgroundLocationResult {
tripId: string | null;
isTracking: boolean;
locations: Coords[];
isLoading: boolean;
error: Error | null;
startTracking: (
customTripId?: string,
options?: TrackingOptions
) => Promise<string | null>;
stopTracking: () => Promise<void>;
refreshLocations: () => Promise<void>;
clearCurrentTrip: () => Promise<void>;
clearError: () => void;
}UseLocationTrackingOptions
interface UseLocationTrackingOptions {
autoStart?: boolean;
tripId?: string;
options?: TrackingOptions;
onTrackingStart?: (tripId: string) => void;
onTrackingStop?: () => void;
onError?: (error: Error) => void;
}UseLocationTrackingResult
interface UseLocationTrackingResult {
isTracking: boolean;
tripId: string | null;
refresh: () => Promise<void>;
isLoading: boolean;
}UseLocationUpdatesOptions
interface UseLocationUpdatesOptions {
tripId?: string;
onLocationUpdate?: (location: Coords) => void;
onUpdateInterval?: number;
onLocationWarning?: (warning: LocationWarningEvent) => void;
onNotificationAction?: (event: NotificationActionEvent) => void;
autoLoad?: boolean;
}UseLocationUpdatesResult
interface UseLocationUpdatesResult {
tripId: string | null;
isTracking: boolean;
locations: Coords[];
lastLocation: Coords | null;
lastWarning: LocationWarningEvent | null;
isLoading: boolean;
error: Error | null;
clearError: () => void;
clearLocations: () => Promise<void>;
}Enums
LocationAccuracy
| Value | Description |
| ------------------------- | ----------------------------------------------------- |
| HIGH_ACCURACY | GPS + sensors. Best accuracy, highest battery usage. |
| BALANCED_POWER_ACCURACY | Balanced accuracy and power consumption. |
| LOW_POWER | Network-based. Lower accuracy, better battery. |
| NO_POWER | Only receives updates requested by other apps. |
| PASSIVE | Passive updates from other apps. No additional power. |
NotificationPriority
| Value | Description |
| --------- | ------------------------------- |
| LOW | Minimal notification (default). |
| DEFAULT | Default system priority. |
| HIGH | More prominent notification. |
| MAX | Urgent notification. |
LocationPermissionStatus
| Value | Description |
| -------------- | -------------------------------------------------------------------------------- |
| GRANTED | All required permissions granted (full background access). |
| WHEN_IN_USE | iOS only: WhenInUse permission granted. Tracking works but may have limitations. |
| DENIED | Permission denied (can request again). |
| BLOCKED | Permission permanently denied (must open settings). |
| UNDETERMINED | Permission not yet requested. |
NotificationPermissionStatus
| Value | Description |
| -------------- | -------------------------------------- |
| GRANTED | Notification permission granted. |
| DENIED | Notification permission denied. |
| UNDETERMINED | Notification permission not yet asked. |
Notification Customization
The foreground service notification supports full visual customization through the notificationOptions field on TrackingOptions (see NotificationOptions table above).
Static defaults can be configured without runtime code using AndroidManifest metadata or convention-named drawables:
<!-- AndroidManifest.xml -->
<meta-data android:name="com.backgroundlocation.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data android:name="com.backgroundlocation.default_notification_color"
android:resource="@color/notification_accent" />Alternatively, place a drawable named bg_location_notification_icon in res/drawable/ for automatic detection.
Resolution priority: Runtime options > AndroidManifest metadata > Convention drawable > System default.
Dynamic updates allow changing notification text while tracking is active:
await BackgroundLocation.updateNotification(
'Delivery #1234',
'Arriving in 5 minutes'
);Action buttons (max 3) can be added via notificationOptions.actions and handled through the onNotificationAction callback in useLocationUpdates.
Documentation
Getting Started
- Quick Start Guide -- Get running in 5 minutes
- Integration Guide -- Detailed setup for existing apps
- iOS Setup Guide -- iOS-specific configuration and requirements
- Hooks Guide -- Complete hooks documentation
- Real-Time Updates -- Event-driven location watching
Production
- Google Play Compliance -- Required steps for Play Store approval
- App Store Compliance -- Required steps for App Store approval (iOS)
- Battery Optimization -- Platform-specific battery management
- Crash Recovery -- Session persistence and recovery strategies
- Platform Comparison -- Android vs iOS behavior differences
Development
- Testing Guide -- Test structure and guidelines
- CI/CD Guide -- Automated pipelines
- Publishing Guide -- How to publish to npm
- Realtime Debug Guide -- Debugging location updates
- Implementation Summary -- Technical architecture overview
Platform Support
| Platform | Status | Notes | | -------- | --------- | ------------------------------------------------------------------- | | Android | Supported | Kotlin native implementation. Min SDK 24, target SDK 34. | | iOS | Supported | Swift native implementation. CLLocationManager, Core Data, iOS 13+. |
iOS: Background tracking on iOS uses the system blue status bar indicator instead of a notification. The
notificationOptionsfield inTrackingOptionsis Android-only and is silently ignored on iOS. See Platform Comparison for detailed differences.
Contributing
Contributions are welcome. See the Contributing Guide for development workflow, coding standards, and how to submit pull requests.
License
MIT
