Skip to content
Support the creatorSupport

Quick start

This gets a device recording a fix every 30 seconds while moving and every 3 minutes while parked, and uploading to your endpoint once a minute.

tracking.ts
import LongPing from 'react-native-long-ping';
// On every app launch (safe to repeat: never starts, stops or prompts).
export async function setUpTracking(token: string) {
await LongPing.configure({
movingIntervalSec: 30,
parkedIntervalSec: 180,
http: {
url: 'https://api.example.com/locations',
batch: true,
uploadIntervalSec: 60,
},
notification: { title: 'On duty', text: 'Sharing your location with dispatch' },
});
await LongPing.setAuthorization({ accessToken: token });
}
// When the driver goes on duty.
export async function goOnDuty() {
// Your own rationale screen first, then:
await LongPing.requestPermission('always');
await LongPing.start();
}
// When the driver goes off duty.
export async function goOffDuty() {
await LongPing.stop(); // queued records still upload
}

And somewhere in your UI, if you want to show what is happening:

useEffect(() => {
const subs = [
LongPing.onLocation((location) => console.log('fix', location.timestamp, location.coords)),
LongPing.onMotionChange(({ isMoving }) => console.log(isMoving ? 'moving' : 'parked')),
LongPing.onHttp(({ status, count }) => console.log('upload', status, count)),
];
return () => subs.forEach((s) => s.remove());
}, []);
  1. configure() replaces the whole config with the defaults plus what you pass, validates it, saves it on the device and applies it. It never starts, stops or prompts, so call it on every launch. A bad value rejects with INVALID_CONFIG and the key in the message.

  2. setAuthorization() stores your access token in the Keychain (iOS) or an Android Keystore-backed store. Every upload carries Authorization: Bearer <token>. See Authentication & token refresh for refresh tokens.

  3. requestPermission('always') shows the OS permission flow. It is the only call that ever shows a dialog. See Permissions.

  4. start() checks permission and location services, saves enabled = true, and records an immediate motionchange fix in the moving state. From then on a fix is recorded every movingIntervalSec (30 s). After 5 minutes inside a 75 m radius (stopTimeoutSec, stopRadiusM) it switches to parked and records every parkedIntervalSec (180 s). Calling start() when tracking is already on is safe.

  5. Uploads go to http.url at most once every uploadIntervalSec (60 s), as {"locations": [ … ]}. Any 2xx reply deletes the sent records from the on-device queue.

The smallest possible receiver, to watch the first batch arrive:

server.mjs
import { createServer } from 'node:http';
createServer((req, res) => {
let body = '';
req.on('data', (chunk) => (body += chunk));
req.on('end', () => {
const { locations = [] } = JSON.parse(body || '{}');
for (const l of locations) console.log(l.timestamp, l.event, l.coords.latitude, l.coords.longitude);
res.writeHead(200, { 'content-type': 'application/json' }).end('{}');
});
}).listen(8787);

For real servers (deduplication, auth, replies) see Receiving uploads on your server.