Background location that doesn't go quiet.

React Native background location for iOS and Android. Long Ping records GPS on a clock you set, every 5 seconds or every 10 minutes, and gets every fix to your server through dead zones, app kills and reboots, even while JavaScript is frozen.

npm install react-native-long-ping

Free and open source. No license key, no paid tier.

  • iOS 15.1+
  • Android 7.0+ (API 24)
  • React Native 0.76+ (New Architecture)
  • MIT license

A clock, not a guess

The same shift, two ways of deciding when to record.

A motion-triggered background geolocation tracker sleeps when the phone's motion detector says "still" and wakes when it says "moving". When that detector gets stuck, the tracker sleeps while the van drives. Long Ping records on a fixed clock and works out moving or parked from the fixes themselves, using speed and distance.

Fix while movingFix while parkedMotion changeNo fixes

What the van did

DrivingStopDrivingStopDrivingStopDriving

Motion-triggered tracker

Silent for 2 h 44 mDetector stuck on "still" while the van drove

Long Ping

Motion-triggered

Fixes in 6 h
175
Longest gap
2 h 44 m
Fixes, 09:30–11:10 drive
0

Long Ping

Fixes in 6 h
301
Longest gap
5 min
Fixes, 09:30–11:10 drive
100

An illustration of a failure mode, not a benchmark. The Long Ping row follows the plugin's rules withmovingIntervalSec: 60, parkedIntervalSec: 300 and the defaultstopTimeoutSec of 300: after 5 minutes inside the stop radius it switches to the parked clock, and the first fast fix switches it back.

Intervals & battery

Pick a clock. See what it costs.

Fixes, uploads and data follow straight from your settings. Battery is an estimate until device measurements are in, and it is labelled that way.

30 s

movingIntervalSec · 1 s and up

3 min

parkedIntervalSec · default 180 s

8 h
3 h

Driving + parked ≤ 24 h. The rest of the day tracking is off.

1 min

http.uploadIntervalSec · 0 = upload as soon as a fix is recorded

Assumes batching on (maxBatchSize 100), about 360 bytes per default record and about 1 KB of HTTP headers per request. Motion-change fixes, TLS and your own extras are not counted.

Fixes per day

1,020

Upload requests per day

540

Data per day

≈ 907 KB

Battery

Estimate · pending device measurements
While moving3–6 %/h
While parked1–2 %/h
Over the tracked day27–54 %

Anchor points: moving every 5 s ≈ 5–10 %/h, every 30 s ≈ 3–6 %/h, every 60 s or longer ≈ 1.5–3 %/h (iOS drops to low power between fixes from 60 s); parked every 3 min ≈ 1–2 %/h. Values between anchors are interpolated. Real numbers depend on the phone, signal, screen and the rest of your app.

Your config

await LongPing.configure({
  movingIntervalSec: 30,
  parkedIntervalSec: 180,
  http: {
    url: 'https://api.example.com/locations',
    uploadIntervalSec: 60,
  },
});

Payload playground

Your server. Your JSON.

Flip the options and see the exact body your endpoint receives. Then pick a reply and see what the device does with it.

Mode

http.batch: true · up to maxBatchSize records per request

Tokens become raw JSON values. Strings go in without quotes, so write"{{timestamp}}" yourself.

Your server receives

1 request · 2 records

Pretty-printed here; the device sends compact JSON.

You reply

How it works

Native from the clock to your server and back.

JavaScript configures it, hands over tokens and listens if it wants to. Everything in this loop runs in Kotlin and Swift, so it keeps going when the JS thread is frozen, killed or never started.

  1. 01

    Clock

    A fix is due every movingIntervalSec or parkedIntervalSec. lowBattery can stretch it.

  2. 02

    Fix

    From the fused provider (Android) or CoreLocation (iOS). Worse than minAccuracyM? Skipped, unless the fix is overdue.

  3. 03

    Moving or parked

    Speed and distance decide: movingSpeedMps, stopRadiusM, stopTimeoutSec. No OS activity classifier.

  4. 04

    Record

    A JSON record with a uuid, coords, battery and your extras. Emitted to JS if a listener exists.

  5. 05

    SQLite queue

    On disk, oldest first. Survives kills and reboots. Pruned at maxRecords and maxDays.

  6. 06

    Uploader

    Batches up to maxBatchSize, one upload at a time, backoff with jitter, token refresh.

  7. 07

    Your server

    Default record or your locationTemplate. Any 2xx deletes the sent records.

  8. 08

    Remote config

    long_ping.config in the reply is merged live; long_ping.stop stops tracking. Back to the clock.

When something kills it

Watchdog, both platforms

Every 60 s while tracking. No fix for max(2 × interval, interval + 60 s)? It logs that and restarts location updates. It also kicks uploads and prunes the log.

Android

A foreground service with START_STICKY. A boot receiver restarts tracking after a reboot or app update (startOnBoot). A WorkManager check every 15 minutes restarts the service if it is gone.

iOS

Significant-change monitoring, plus a region around the parked spot, relaunch a terminated app. The engine resumes at launch, before your JavaScript loads.

What you get

Built for "where is the van?" at 3 a.m.

GPS tracking for fleet, delivery and field-service apps on iOS and Android, where a phone that goes quiet means a van nobody can find.

  • Completely free. Open source.

    Free for personal and commercial use. No license key, no paid tier, no limits. MIT license.

    License
  • Any interval from 1 second

    One clock for moving, one for parked, plus an optional low-battery floor. Change them live with setConfig() or from your server.

    Docs
  • Moving or parked, from the fixes

    Speed and displacement decide, never an OS motion classifier. Tune it with movingSpeedMps, stopRadiusM and stopTimeoutSec.

    Docs
  • Native end to end

    Fixes, queue, uploads and restarts run in Kotlin and Swift. JavaScript can be frozen, killed or never started.

    Docs
  • A queue that waits out dead zones

    SQLite on the device, batching, exponential backoff with jitter, Retry-After, 413 halving. Keeps 10,000 records or 7 days by default.

    Docs
  • A 401 never stops tracking

    Tokens refresh through your refreshUrl. If that fails, uploads pause and fixes keep recording until you hand over a new token.

    Docs
  • Your server, your JSON

    The default record or your own locationTemplate, with params, extras and rootProperty. No hosted backend.

    Docs
  • Steer devices from your server

    Add long_ping to any 2xx reply to change intervals or stop a device. No app release, even with the app in the background.

    Docs
  • Recovers on its own

    Android restarts after reboots, app updates and service kills. iOS relaunches after termination on significant movement.

    Docs
  • Explains its silences

    An on-device log of every state change, restart, upload and rejected fix. Read it with logger.getLog().

    Docs

Platform limits

What the OS still decides.

No plugin gets around these. Knowing them up front is cheaper than finding them in the field, so here they are.

iOS

  • Location updates stay on the whole time tracking is on. That is what keeps an app alive in the background on iOS. Between fixes Long Ping drops to a low-power mode when the interval is 60 s or more.
  • If the user swipes the app away, iOS stops it until the device moves a few hundred meters. Then iOS relaunches it and tracking resumes without your JavaScript.
  • Needs UIBackgroundModes → location in Info.plist. Without it, tracking is foreground-only and the log says so.
  • Users can pick "While Using" or approximate location. getProviderState() tells you which.

Android

  • OEM battery managers (Samsung, Xiaomi, Huawei and others) can freeze any app. deviceSettings.openPowerManagerSettings() opens the right screen; dontkillmyapp.com explains each brand.
  • On Android 13+ your app has to ask for POST_NOTIFICATIONS, or the tracking notification is hidden.
  • Android 12+ can refuse to start a foreground service from the background. Long Ping catches it, logs it and retries at the next 15-minute check.
  • v0.1 uses the fused location provider only, so devices without Google Play Services get no location.

Not in the box.

No geofencing API, no Expo config plugin, no web support and no hosted backend. It posts to your server, and that's the point.

FAQ

Short answers.

The docs have the long ones.

Open the docs
Is it really free?

Yes, completely. Free for personal and commercial use. No license key, no paid tier, no limits. Long Ping is open source under the MIT license, and there is no hosted service to pay for either: it uploads to your own server.

Does it keep tracking when the app is killed?

On Android, yes: the foreground service is restarted by the system, by the 15-minute check and after reboots. On iOS, if the user swipes the app away, iOS stops it until the device moves a few hundred meters, then relaunches it and tracking resumes on its own. Set stopOnTerminate: true if you want swipe-away to stop tracking instead.

What happens with no signal?

Fixes keep being recorded into a SQLite queue on the device (10,000 records or 7 days by default, both configurable). When connectivity returns, the queue uploads oldest first, in batches.

What if the access token expires mid-shift?

On a 401 or 403 the plugin refreshes the token through your refreshUrl and retries. If it cannot, uploads pause until you call setAuthorization() (or 15 minutes pass) and the authorization event fires. Location never stops.

How much battery does it use?

It depends mostly on the moving interval. Use the calculator above for an estimate; real numbers from device measurements will replace the estimates when testing is done.

Can I change intervals without shipping an app update?

Yes. Put {"long_ping": {"config": {…}}} in any 2xx upload reply and the device merges it right away, even in the background. {"long_ping": {"stop": true}} stops tracking.

Does it work with Expo?

There is no Expo config plugin, and it cannot run in Expo Go because it is a native module. It is built for React Native 0.76+ with the New Architecture.

Does it do geofencing or run on the web?

No. Long Ping does one job: location on a clock, delivered to your server. There is no geofencing API and no web support.

Put it on one van this week.

Install it, point it at an endpoint, drive around the block, read the log.

npm install react-native-long-ping
Quick start