Documentation
Everything you need to integrate background location tracking into your Capacitor app. The native core stays the same. The wrapper and setup flow adapt to your stack.
Quick Install
npm install @bglocation/capacitornpx cap syncKeep capacitor.config.ts in sync with your native apps and rerun sync after changing plugin config or license settings.
Getting Started
Install the Capacitor wrapper, configure tracking, and get your first location update in under 5 minutes.
1. Install
npm install @bglocation/capacitor npx cap sync
2. Configure & Start
import { BackgroundLocation } from '@bglocation/capacitor';
await BackgroundLocation.configure({
distanceFilter: 15,
desiredAccuracy: 'high',
heartbeatInterval: 15,
locationUpdateInterval: 5000,
debug: true,
});
BackgroundLocation.addListener('onLocation', (location) => {
console.log(location.latitude, location.longitude);
});
await BackgroundLocation.start();3. Stop Tracking
await BackgroundLocation.stop(); await BackgroundLocation.removeAllListeners();
Permissions
On Android 10+, request foreground permission first, then background. On iOS, call requestPermissions() and let the system handle the Always vs When In Use flow.
React Native support targets 0.76+ with the New Architecture and TurboModules.
Configuration
All options available in configure(). The Capacitor 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 BackgroundLocation.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/capacitor.
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() | Promise<void> | Remove all active event listeners registered through the wrapper. |
Events
Register listeners via BackgroundLocation.addListener(event, handler).
| 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
Capacitor apps still need the usual location usage descriptions in the host app's 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>
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
The Capacitor plugin contributes its manifest entries automatically during sync and manifest merge.
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 BackgroundLocation.requestPermissions({
permissions: ['location'],
});
await BackgroundLocation.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
Place the key in capacitor.config.ts and rerun sync.
// capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.yourcompany.app',
plugins: {
BackgroundLocation: {
licenseKey: 'BGL1-eyJ...',
},
},
};
export default config;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 BackgroundLocation.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 { BackgroundLocation } from '@bglocation/capacitor';
await BackgroundLocation.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 },
},
});
BackgroundLocation.addListener('onHttp', (event) => {
if (!event.success) {
console.warn('Buffered:', event.bufferedCount);
}
});
await BackgroundLocation.start();Fitness / Running App
High-frequency tracking with in-memory processing for pace, route, and progress stats.
import { BackgroundLocation } from '@bglocation/capacitor';
import type { Location } from '@bglocation/capacitor';
const route: Location[] = [];
await BackgroundLocation.configure({
distanceFilter: 5,
desiredAccuracy: 'high',
heartbeatInterval: 10,
locationUpdateInterval: 3000,
});
BackgroundLocation.addListener('onLocation', (location) => {
route.push(location);
updateMapPolyline(route);
});
await BackgroundLocation.start();Geofencing — Points of Interest
Register circular regions and react to enter, exit, and dwell transitions.
import { BackgroundLocation } from '@bglocation/capacitor';
await BackgroundLocation.configure({
distanceFilter: 50,
desiredAccuracy: 'balanced',
heartbeatInterval: 60,
});
await BackgroundLocation.addGeofence({
identifier: 'office',
latitude: 52.2297,
longitude: 21.0122,
radius: 100,
notifyOnEntry: true,
notifyOnExit: true,
});
BackgroundLocation.addListener('onGeofence', (event) => {
console.log(event.identifier, event.action);
});
await BackgroundLocation.start();