react-native-fitness-geolocation
v3.0.1
Published
Production-grade React Native fitness GPS — background tracking, geofencing, schedules, HTTP sync, native SQLite. MIT alternative to Transistorsoft.
Maintainers
Readme
react-native-fitness-geolocation
Production-grade React Native GPS for fitness and activity tracking apps — background location, native SQLite persistence, motion auto-pause, and Live Activities.
Built as an open-source (MIT) alternative to Transistorsoft react-native-background-geolocation, tailored specifically for high-frequency fitness apps (like Strava or Nike Run Club).
npm install react-native-fitness-geolocation
cd ios && pod installWhy this package?
Building a reliable background location tracking library for React Native is incredibly difficult due to aggressive OS-level battery optimizations. This package solves the two hardest problems natively:
- Native SQLite Persistence: Both iOS and Android store coordinates natively first, then drain them to the JS thread. No data is lost if the React Native bridge crashes or is paused by the OS.
- Battery-Conscious Motion Detection: Includes native
MotionEngines (CoreMotion / Activity Recognition) that automatically suspend the GPS hardware when the user is stationary to save battery, waking it up when they resume moving. - Fitness-First: Includes a C++
TrackEnginefor high-performance distance filtering, anIntelligentAutoPauseEnginefor cycling/running, and built-in support for iOS 16+ Live Activities.
It offers two APIs: a standard drop-in replacement for @react-native-community/geolocation, and a powerful BackgroundGeolocation API for full workout orchestration.
Platform support
| Feature | iOS | Android |
|---------|-----|---------|
| getCurrentPosition / watchPosition | ✅ | ✅ |
| Background GPS + SQLite queue | ✅ | ✅ |
| Built-in foreground tracking service | — | ✅ |
| Foreground queue replay | ✅ | ✅ |
| Watch restore after app restart | ✅ | ✅ |
| distanceFilter, interval, maximumAge | ✅ | ✅ |
| Motion auto-pause (MotionEngine) | ✅ | 🚧 scaffold |
| CLBackgroundActivitySession (iOS 17+) | ✅ | — |
Quick start
import Geolocation from 'react-native-fitness-geolocation';
// One-shot location (map pin, start screen)
Geolocation.getCurrentPosition(
position => console.log(position.coords),
error => console.warn(error),
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
);
// Continuous tracking (run / ride / hike)
const watchId = Geolocation.watchPosition(
position => saveRoutePoint(position),
error => console.warn(error),
{
enableHighAccuracy: true,
distanceFilter: 5,
interval: 3000,
fastestInterval: 1000,
showsBackgroundLocationIndicator: true, // iOS
},
);
// Stop
Geolocation.clearWatch(watchId);Permissions
Use built-in helpers or your own flow:
import { PermissionManager } from 'react-native-fitness-geolocation';
const result = await PermissionManager.requestFitnessPermissions({
includeMotion: true, // Android ACTIVITY_RECOGNITION
});
if (result.status !== 'ready') {
await PermissionManager.openSettings();
}Or configure once (community-geolocation compatible):
Geolocation.setRNConfiguration({
skipPermissionRequests: false,
authorizationLevel: 'always', // fitness apps
});Background tracking
GPS continues in the background. Points collected while JS is suspended are stored in native SQLite and replayed when the app returns to foreground — no data loss on lock screen.
// Manual sync (usually automatic via AppState)
const count = await Geolocation.syncPendingLocations();
console.log(`Delivered ${count} queued points`);Production lifecycle API
For workout recording, use the native-first lifecycle API. This gives the app a clear state machine: configure, subscribe, start native recording, sync the native SQLite queue, then stop.
import { BackgroundGeolocation } from 'react-native-fitness-geolocation';
const sub = BackgroundGeolocation.onLocation(
async location => {
await saveCoordinateToRealm(location);
},
error => console.warn(error),
);
await BackgroundGeolocation.ready({
authorizationLevel: 'always',
enableHighAccuracy: true,
desiredAccuracy: 10,
distanceFilter: 0,
locationUpdateInterval: 1000,
fastestLocationUpdateInterval: 1000,
trackingMode: 'fitness',
pausesLocationUpdatesAutomatically: false,
showsBackgroundLocationIndicator: true,
notificationTitle: 'Activity tracking active',
notificationText: 'Recording your route in the background',
});
await BackgroundGeolocation.start();
// End workout
await BackgroundGeolocation.sync();
await BackgroundGeolocation.stop();
sub.remove();For device testing, subscribe to native diagnostics:
const diagnosticSub = BackgroundGeolocation.onDiagnostic(event => {
console.log('[FitnessGeo]', event.event, event);
});
const history = await BackgroundGeolocation.getDiagnostics();Useful events include location-raw, location-drop, location-persist, persist-failed, watch-start, watch-stop, watch-restore, foreground, and authorization-change.
Required setup: See docs/SETUP.md for Info.plist and AndroidManifest snippets.
Verify your app:
npx react-native-fitness-geolocation verify-setupFitness apps (optional layer)
For full workout orchestration — permissions + GPS + motion + auto-pause:
import { createFitnessEngine } from 'react-native-fitness-geolocation';
const engine = createFitnessEngine({ autoPause: true, includePedometer: false });
await engine.prepare();
engine.start(
position => onLocation(position),
error => onError(error),
{ trackingMode: 'fitness' },
);
// Later
engine.stop();FitnessEngine is optional. Plain Geolocation.watchPosition works for any app.
Migration from @react-native-community/geolocation
- import Geolocation from '@react-native-community/geolocation';
+ import Geolocation from 'react-native-fitness-geolocation';Same API: getCurrentPosition, watchPosition, clearWatch, requestAuthorization, setRNConfiguration.
See docs/MIGRATION.md for options matrix and edge cases.
API reference
Geolocation (default export)
| Method | Description |
|--------|-------------|
| getCurrentPosition(success, error?, options?) | Single fix with timeout, maximumAge |
| watchPosition(success, error?, options?) → number | Continuous updates |
| clearWatch(id) | Stop one watch |
| stopObserving() | Stop all watches |
| requestAuthorization(level?) | 'whenInUse' | 'always' |
| getAuthorizationStatus() | { status, always } |
| setRNConfiguration(config) | Global config |
| syncPendingLocations() | Drain SQLite queue to callbacks |
| getQueueSize() | Pending point count |
| addAuthorizationListener(cb) | Permission change events |
Options (GeolocationOptions)
| Option | Default | Notes |
|--------|---------|-------|
| timeout | 15000 | ms, emits error code 3 |
| maximumAge | 0 | Accept cached fix if younger (ms) |
| enableHighAccuracy | true | |
| desiredAccuracy | — | native accuracy target in meters |
| distanceFilter | 5 | meters |
| distanceFilter: 0 | — | densest route recording; useful for Strava-style workouts |
| interval | 3000 | Android update interval (ms); iOS is distance/accuracy driven |
| locationUpdateInterval | — | alias for background-geolocation style Android configs |
| fastestInterval | 1000 | Android min interval (ms) |
| fastestLocationUpdateInterval | — | alias for background-geolocation style Android configs |
| trackingMode | — | fitness | navigation | balanced | low_power |
| enableMotion | false | Opt-in motion engine with watch |
Error codes (PositionError)
| Code | Constant | Meaning |
|------|----------|---------|
| 1 | PERMISSION_DENIED | User denied location |
| 2 | POSITION_UNAVAILABLE | GPS unavailable |
| 3 | TIMEOUT | Request timed out |
Android Background & OEM Devices
For long sessions with the screen off, Android requires a foreground service with a persistent notification. This package ships its own location foreground service, native GPS pipeline, and SQLite queue, so activity tracking does not depend on debug JS threads.
For smooth workout polylines, prefer enableHighAccuracy: true, distanceFilter: 0 to 5, trackingMode: 'fitness', and pausesLocationUpdatesAutomatically: false.
A Note on OEM Fragmentation:
Android manufacturers (Samsung, Xiaomi, Huawei, OnePlus) employ aggressive, non-standard battery optimizations that often kill background services after 15-30 minutes. This package includes an OemProfiles manager and a BatteryOptimizationManager to mitigate this, but developers must be aware of OEM limits. You may still need to instruct users to disable "Battery Optimization" for your app in their device settings for flawless marathon tracking.
Docs
| Doc | Description | |-----|-------------| | docs/SETUP.md | Platform permissions | | docs/MIGRATION.md | From community geolocation | | docs/PRODUCTION.md | Production checklist | | docs/PUBLISH.md | npm publish |
Requirements
- React Native ≥ 0.73
- iOS 13+ (iOS 17+ for background activity session)
- Android API 24+
- Bare workflow or Expo dev client (native module)
MIT · Arslan Khan
