Documentation
Everything you need to integrate background location tracking into your React Native app. The native core stays the same. The wrapper and setup flow adapt to your stack.
Quick Install
npm install @bglocation/react-nativenpx expo prebuildExpo projects should use the config plugin plus a dev client. Bare React Native apps still need cd ios && pod install after installation.
Getting Started
Install the React Native wrapper, configure tracking, and get your first location update in under 5 minutes.
1. Install
npm install @bglocation/react-native npx expo prebuild # Bare React Native cd ios && pod install
2. Configure & Start
import {
addListener,
configure,
start,
} from '@bglocation/react-native';
await configure({
distanceFilter: 15,
desiredAccuracy: 'high',
heartbeatInterval: 15,
locationUpdateInterval: 5000,
debug: true,
});
const locationSubscription = addListener('onLocation', (location) => {
console.log(location.latitude, location.longitude);
});
await start();
// later
locationSubscription.remove();3. Stop Tracking
import { removeAllListeners, stop } from '@bglocation/react-native';
await stop();
removeAllListeners();Permissions
The React Native wrapper uses the same permission model. Expo projects need a dev client and the config plugin. Bare React Native apps can request permissions through the exported requestPermissions() function after native setup is in place.
React Native support targets 0.76+ with the New Architecture and TurboModules.
Configuration
All options available in configure(). The React Native wrapper mirrors the same native config surface and merges partial updates.
Core Options
| Option | Type | Default | Description |
|---|---|---|---|
distanceFilter | number | 'auto' | 15 | Minimum distance in meters between updates, or 'auto' for speed-adaptive mode. |
desiredAccuracy | 'high' | 'balanced' | 'low' | 'high' | Accuracy preset used by the native location manager. |
heartbeatInterval | number | 15 | Heartbeat interval in seconds. Fires even when stationary. |
locationUpdateInterval | number | 5000 | Android-only update interval in milliseconds. |
fastestLocationUpdateInterval | number | 2000 | Android-only lower bound for high-frequency updates. |
debug | boolean | false | Enables verbose logs and onDebug events. |
HTTP Posting
Native HTTP delivery works the same in Capacitor and React Native. The JavaScript wrapper configures it once, then URLSession on iOS and HttpURLConnection on Android post directly from the native layer.
await configure({
distanceFilter: 15,
desiredAccuracy: 'high',
heartbeatInterval: 15,
locationUpdateInterval: 5000,
fastestLocationUpdateInterval: 2000,
http: {
url: 'https://api.example.com/locations',
headers: { Authorization: 'Bearer <token>' },
buffer: { maxSize: 1000 },
},
});HTTP POST Body
{
"location": {
"latitude": 52.2297,
"longitude": 21.0122,
"accuracy": 5.0,
"speed": 1.2,
"heading": 180.0,
"altitude": 110.5,
"timestamp": 1700000000000,
"isMoving": true,
"isMock": false
}
}HttpEvent
interface HttpEvent {
statusCode: number;
success: boolean;
responseText: string;
error?: string;
bufferedCount?: number;
}Offline Buffer & Retry
Failed POSTs are stored in SQLite when buffer.maxSizeis configured. Buffered locations flush automatically in FIFO order after the next successful request.
Adaptive Distance Filter
Use auto mode to target stable update intervals regardless of whether the user is walking, cycling, or driving.
distanceFilter: 'auto',
autoDistanceFilter: {
targetInterval: 10,
minDistance: 10,
maxDistance: 500,
}Notification (Android)
Android tracking runs as a foreground service. Customize the persistent notification text from the wrapper.
notification: {
title: 'Background Location',
text: 'Tracking your route',
}Partial Reconfiguration
Subsequent configure() calls merge with the last applied config. Pass only the fields you want to change.
API Reference
Complete TypeScript API exported by @bglocation/react-native.
Methods
| Method | Returns | Description |
|---|---|---|
getVersion() | Promise<VersionInfo> | Get wrapper and native core version information. |
checkPermissions() | Promise<LocationPermissionStatus> | Check current foreground and background permission state. |
requestPermissions(options?) | Promise<LocationPermissionStatus> | Request foreground or background location permissions. |
configure(options) | Promise<ConfigureResult> | Configure tracking before start(); partial updates are merged. |
start() | Promise<LocationState> | Start background location tracking. |
stop() | Promise<LocationState> | Stop background location tracking. |
getState() | Promise<LocationState> | Read the current enabled/tracking state. |
getCurrentPosition(options?) | Promise<Location> | Request a single location update. |
addGeofence(geofence) | Promise<void> | Register one geofence region. |
addGeofences({ geofences }) | Promise<void> | Register multiple geofences atomically. |
removeGeofence({ identifier }) | Promise<void> | Remove a geofence by identifier. |
removeAllGeofences() | Promise<void> | Clear all geofences. |
getGeofences() | Promise<{ geofences: Geofence[] }> | Return the currently registered geofences. |
checkBatteryOptimization() | Promise<BatteryWarningEvent> | Inspect Android battery optimization state. |
requestBatteryOptimization() | Promise<BatteryWarningEvent> | Open Android battery optimization settings. |
removeAllListeners() | void | Remove all active event listeners registered through the wrapper. |
Events
Register listeners via addListener(event, handler) and keep the returned Subscription so you can remove it later.
| Event | Payload | Description |
|---|---|---|
onLocation | Location | Location update based on distanceFilter. |
onHeartbeat | HeartbeatEvent | Periodic heartbeat, even when stationary. |
onProviderChange | ProviderChangeEvent | GPS/network provider status changed. |
onHttp | HttpEvent | Native HTTP POST result. |
onDebug | DebugEvent | Debug log message when debug mode is enabled. |
onBatteryWarning | BatteryWarningEvent | Battery optimization warning on Android. |
onAccuracyWarning | AccuracyWarningEvent | Approximate location warning on iOS 14+. |
onMockLocation | MockLocationEvent | Mock location detected on Android. |
onPermissionRationale | PermissionRationaleEvent | Show a custom rationale before background permission. |
onTrialExpired | TrialExpiredEvent | Trial session ended and tracking stopped automatically. |
onGeofence | GeofenceEvent | Geofence transition: enter, exit, or dwell. |
Location Object
interface Location {
latitude: number;
longitude: number;
accuracy: number;
speed: number;
heading: number;
altitude: number;
timestamp: number;
isMoving: boolean;
isMock: boolean;
effectiveDistanceFilter?: number;
}Geofencing
Geofencing is available through the same API surface in both wrappers. Up to 20 regions can be active at once.
interface Geofence {
identifier: string;
latitude: number;
longitude: number;
radius: number;
notifyOnEntry?: boolean;
notifyOnExit?: boolean;
notifyOnDwell?: boolean;
dwellDelay?: number;
extras?: Record<string, string>;
}GeofenceEvent Interface
interface GeofenceEvent {
identifier: string;
action: 'enter' | 'exit' | 'dwell';
location: Location | null;
extras?: Record<string, string>;
timestamp: number;
}Error Codes
| Code | Description |
|---|---|
NOT_CONFIGURED | configure() must run before adding geofences. |
GEOFENCE_LIMIT_EXCEEDED | The wrapper enforces the 20 geofence limit. |
GEOFENCE_ERROR | Native registration failed. |
UNSUPPORTED | The current runtime does not support the attempted native operation. |
Platform Guides
Platform-specific setup for iOS and Android. The native core is the same, but the wrapper decides how much gets automated for you.
iOS
Info.plist — Required Keys
Expo projects can generate these values through the config plugin. Bare React Native apps should add them directly in Info.plist.
<key>NSLocationWhenInUseUsageDescription</key> <string>We need your location to track your route.</string> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>Background location is needed for continuous tracking.</string>
Background Modes
Enable Location updates in Xcode. Expo users get this automatically after expo prebuild when the config plugin is configured.
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
Expo Config Plugin
The React Native package ships with an Expo config plugin that injects permissions, background modes, and the license key during prebuild.
{
"expo": {
"plugins": [
[
"@bglocation/react-native",
{
"licenseKey": "BGL1-eyJ...",
"locationWhenInUsePermission": "We use your location to track your route.",
"locationAlwaysPermission": "We use your location in the background for continuous tracking."
}
]
]
}
}SLC Fallback
Significant Location Change monitoring is registered automatically. If iOS kills the app, the native core uses SLC to relaunch and resume standard GPS tracking.
Minimum Deployment Target
iOS 15.0+.
Android
Permissions
Expo prebuild or the Android manifest merger will add the required permissions from the React Native package.
ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION ACCESS_BACKGROUND_LOCATION FOREGROUND_SERVICE FOREGROUND_SERVICE_LOCATION POST_NOTIFICATIONS
Foreground Service
Tracking runs inside a foreground service with a persistent notification. This is what keeps Android from killing the process during long sessions.
Battery Optimization
OEM battery killers are detected automatically. The wrapper emits onBatteryWarning with an OEM-specific help URL.
Two-Step Permission Flow
await requestPermissions({
permissions: ['location'],
});
await requestPermissions({
permissions: ['backgroundLocation'],
});Minimum SDK
minSdk 26 (Android 8.0), compileSdk 36.
Licensing
Trial mode, offline validation, bundle ID binding, and where to place your license key.
Trial Mode
- 30-minute sessions with automatic stop and an
onTrialExpiredevent. - 1-hour cooldown between trial sessions.
- Debug mode is forced on so you can inspect behavior before buying.
Adding a License Key
Expo users should configure the package plugin. Bare React Native apps can set the same value directly in native config.
{
"expo": {
"plugins": [
[
"@bglocation/react-native",
{
"licenseKey": "BGL1-eyJ..."
}
]
]
}
}<!-- iOS Info.plist --> <key>BGLocationLicenseKey</key> <string>BGL1-eyJ...</string> <!-- AndroidManifest.xml --> <meta-data android:name="dev.bglocation.LICENSE_KEY" android:value="BGL1-eyJ..." />
How Validation Works
- RSA-2048 signed payloads are verified fully offline on-device.
- The license is bound to a bundle ID and can be used across the Capacitor and React Native wrappers for the same app identifier.
- The license itself is perpetual. One year of updates is included, then update access can be renewed.
License Status
const result = await configure({ ... });
// result.licenseMode: 'full' | 'trial'
// result.licenseUpdatesUntil?: string
// result.licenseUpdateExpired?: boolean
// result.licenseError?: stringExamples
Real-world integration patterns for common production use cases.
Fleet / Delivery Tracking
Continuous tracking with native HTTP posting and automatic offline buffering.
import { addListener, configure, start } from '@bglocation/react-native';
await configure({
distanceFilter: 'auto',
autoDistanceFilter: {
targetInterval: 10,
minDistance: 10,
maxDistance: 500,
},
desiredAccuracy: 'high',
heartbeatInterval: 30,
http: {
url: 'https://api.fleet.com/vehicle/location',
headers: { Authorization: 'Bearer <token>' },
buffer: { maxSize: 2000 },
},
});
addListener('onHttp', (event) => {
if (!event.success) {
console.warn('Buffered:', event.bufferedCount);
}
});
await start();Fitness / Running App
High-frequency tracking with in-memory processing for pace, route, and progress stats.
import {
addListener,
configure,
start,
} from '@bglocation/react-native';
import type { Location } from '@bglocation/react-native';
const route: Location[] = [];
await configure({
distanceFilter: 5,
desiredAccuracy: 'high',
heartbeatInterval: 10,
locationUpdateInterval: 3000,
});
addListener('onLocation', (location) => {
route.push(location);
updateMapPolyline(route);
});
await start();Geofencing — Points of Interest
Register circular regions and react to enter, exit, and dwell transitions.
import {
addGeofence,
addListener,
configure,
start,
} from '@bglocation/react-native';
await configure({
distanceFilter: 50,
desiredAccuracy: 'balanced',
heartbeatInterval: 60,
});
await addGeofence({
identifier: 'office',
latitude: 52.2297,
longitude: 21.0122,
radius: 100,
notifyOnEntry: true,
notifyOnExit: true,
});
addListener('onGeofence', (event) => {
console.log(event.identifier, event.action);
});
await start();