Skip to main content

React Native SDK Usage & Integration

The DoorstepAI SDK has four touchpoints in your driver app. Wire up each one and you're done. Everything else on this page is reference detail for those four calls.

#When this happens in the driver appWhat you call
1App launchesInitialize SDK
2Driver enters the ≥250 m delivery geofenceStart Tracking
3Driver takes POD or confirms drop-off in-appMark Drop-off
4Driver exits the ≥250 m delivery geofenceStop Tracking
Permissions

Tracking needs runtime location permission on Android. Request it before the first delivery (see Permission Handling). On iOS the system prompts automatically; you can trigger them up front via Requesting Permissions Up-Front (iOS).


1. Initialize SDK

The easiest way to initialize the SDK is the RootDoorstepAI component, which handles initialization and permission requests automatically. RootDoorstepAI is optional as of the latest release. Data collection begins when you call startDelivery*, as long as you initialize the SDK and set the API key elsewhere.

App.js
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { DoorstepAI, RootDoorstepAI } from '@doorstepai/dropoff-sdk';

export default function App() {
return (
<View style={styles.container}>
<RootDoorstepAI
apiKey="your_api_key_here"
notificationTitle="Tracking..."
notificationText="Tracking your delivery"
/>
{/* Your app content */}
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
},
});
API Key Security

Store your API key securely using environment variables or a secure configuration service. Never hardcode API keys in production builds.


2. Start Tracking

Call startDelivery… when the driver enters the delivery geofence, not once inside the building. Use a unique deliveryId per session: a meaningful identifier you can correlate on your side. Wrap calls in try/catch to handle failures such as an invalid key or denied permissions.

Pick whichever address format you have (startDeliveryByPlaceID, startDeliveryByAddress, or startDeliveryByAddressString):

import { DoorstepAI } from '@doorstepai/dropoff-sdk';

// By Google Place ID
await DoorstepAI.startDeliveryByPlaceID('some_place_id', 'delivery_12345');

// By address components
const address = {
streetNumber: '123',
route: 'Main Street',
subPremise: 'Apt 4B',
locality: 'San Francisco',
administrativeAreaLevel1: 'CA',
postalCode: '94102',
};
await DoorstepAI.startDeliveryByAddress(address, 'delivery_12345');

// By single address string, with optional coordinates and knobs
await DoorstepAI.startDeliveryByAddressString(
'123 Main St, Apt 4B, San Francisco, CA 94102',
'delivery_12345',
{
coordinates: { lat: 37.7749, lng: -122.4194 },
timeoutSeconds: 1200,
}
);

Start parameters

Every start method takes a deliveryId plus an optional trailing options object (StartDeliveryOptions):

ParameterTypeDescription
deliveryIdstringRequired. Unique per session; correlate it on your side
timeoutSecondsnumber?Auto-stops tracking after this duration, a backstop if the exit geofence is missed
autoStopAfterDropoffSecondsnumber?Auto-stops this many seconds after markDropoff. Falls back to remote config if omitted
manualForegroundboolean?(Android only, no-op on iOS) When true, the SDK won't promote its tracking service to the foreground; your app must already run its own
coordinatesLatLngObject?(address / addressString variants only) pairs a textual address with a lat/lng you resolved upstream
driverIdstring?Optional driver identifier passed through to session creation, for correlation on your backend
type StartDeliveryOptions = {
coordinates?: LatLngObject; // address-string + address-components only
timeoutSeconds?: number;
autoStopAfterDropoffSeconds?: number;
manualForeground?: boolean; // Android only, no-op on iOS
driverId?: string;
};
Deprecated start methods

startDeliveryByPlusCode and startDeliveryByLatLng are deprecated. Use startDeliveryByAddressString / startDeliveryByAddress with coordinates instead. They remain for backwards compatibility:

await DoorstepAI.startDeliveryByPlusCode('some_plus_code', 'delivery_12345', 1200);

await DoorstepAI.startDeliveryByLatLng(37.7749, -122.4194, 'Apt 4B', 'delivery_12345', 1200);

3. Mark Drop-off

When the driver completes the delivery (takes a POD or confirms drop-off in-app), mark it. markDropoff is the preferred API:

await DoorstepAI.markDropoff('delivery_12345', 'pod'); // or 'non_pod'

markDropoff parameters

ParameterTypeDescription
deliveryIdstringRequired. The session you're marking
dropoffType'pod' | 'non_pod''pod' (proof of delivery captured) or 'non_pod'

Custom Events

Use newEvent to record a custom event on a delivery. Pass an optional timestamp (epoch seconds) to backdate the event; omit it and the event is recorded at "now".

// Recorded at "now"
await DoorstepAI.newEvent('taking_pod', 'delivery_12345');

// Recorded at an explicit time
await DoorstepAI.newEvent('taking_pod', 'delivery_12345', 1720000000);

newEvent parameters

ParameterTypeDescription
eventNamestringRequired. The event to record
deliveryIdstringRequired. The session the event belongs to
timestampnumber?Epoch seconds the event occurred. When provided, the event is recorded at that time instead of "now"

4. Stop Tracking

Call stopDelivery when the driver exits the delivery geofence, not inside the building:

await DoorstepAI.stopDelivery('delivery_12345');

That covers the full lifecycle. The sections below are reference for the calls above.


Advanced APIs

Requesting Permissions Up-Front (iOS)

Trigger the iOS Motion/Fitness + Location permission prompts before the first delivery:

import { Platform } from 'react-native';
import { DoorstepAI } from '@doorstepai/dropoff-sdk';

if (Platform.OS === 'ios') {
// Defaults to "Always" location authorization. Pass false for when-in-use.
await DoorstepAI.requestAllPermissions(true);
}

Remote Logging

Stream SDK logs to DoorstepAI for support investigations:

await DoorstepAI.configureRemoteLogging({
enabled: true,
minLevel: 'warning', // 'debug' | 'info' | 'warning' | 'error'
flushInterval: 30, // seconds
batchSize: 50,
maxQueueSize: 1000,
});

In-SDK Route Geofencing

An opt-in alternative to running your own geofencing: hand the SDK the whole route and it auto-starts and stops a tracking session as the driver enters and exits each stop.

Permissions

Requires location permission. For background operation, also requires "Allow all the time" (Android ACCESS_BACKGROUND_LOCATION) / Always authorization (iOS) — without it, geofences only fire while the app is foregrounded.

How it works

  1. You pass the route as a DeliveryStop[]; the SDK geofences the nearest stops for the route's lifetime.
  2. On ENTER, it auto-starts a session for that stop (same as startDeliveryByAddressString).
  3. You call markDropoff when the driver completes the stop.
  4. On EXIT, the session stops only if markDropoff was called — otherwise it runs until timeoutSeconds, so a false EXIT can't cut a delivery short.
  5. Every auto-start/stop emits a GeofenceSessionEvent you can subscribe to for your UI.
import { DoorstepAI } from '@doorstepai/dropoff-sdk';

const stops = [
{ deliveryId: 'delivery_12345', address: '123 Main St, San Francisco, CA', latitude: 37.7749, longitude: -122.4194 },
{ deliveryId: 'delivery_67890', address: '500 Market St, San Francisco, CA', latitude: 37.7899, longitude: -122.4009 },
];

await DoorstepAI.startRouteGeofencing(stops, { defaultRadiusMeters: 250 });

API reference

MethodDescription
startRouteGeofencing(stops, options?)Begins geofencing for stops. Throws if stops is empty or the SDK isn't initialized/eligible
stopRouteGeofencing()Clears all geofences and stops active route sessions
resumeRouteGeofencingIfNeeded()Restores geofencing from persisted state. Call on every app launch; no-op if no route is active
getMonitoredStops()Returns the stops currently registered (empty array if no route is active)
addGeofenceSessionListener(listener)Subscribe to auto start/stop events. Returns a subscription — call .remove() to unsubscribe

Types

DeliveryStop

A single stop on the route. deliveryId is the same id you pass to markDropoff and stopDelivery.

type DeliveryStop = {
deliveryId: string;
address: string;
latitude: number;
longitude: number;
radiusMeters?: number; // falls back to RouteGeofenceOptions.defaultRadiusMeters (250)
customerId?: string;
driverId?: string;
};

RouteGeofenceOptions

Tuning for the whole route. Every field is optional, so startRouteGeofencing(stops) works with no options.

type RouteGeofenceOptions = {
defaultRadiusMeters?: number; // default 250
timeoutSeconds?: number; // per-session backstop
autoStopAfterDropoffSeconds?: number;
manualForeground?: boolean; // Android only, ignored on iOS
};

GeofenceSessionEvent

type GeofenceSessionEventType = 'STARTED' | 'STOPPED';

type GeofenceSessionEvent = {
deliveryId: string;
type: GeofenceSessionEventType;
reason: string; // e.g. "geofence", "distance", "timeout", "route_cleared"
};

Observing route events

import { useEffect } from 'react';
import { DoorstepAI } from '@doorstepai/dropoff-sdk';

useEffect(() => {
const sub = DoorstepAI.addGeofenceSessionListener((event) => {
console.log(`Route event: ${event.deliveryId} -> ${event.type} (${event.reason})`);
});
return () => sub?.remove();
}, []);

Lifecycle & persistence

Route state is persisted, so geofencing survives process death and OS restarts. Call resumeRouteGeofencingIfNeeded() on every app launch to restore it — no-op if no route is active.

The SDK handles the rest automatically: it absorbs GPS jitter, tightens location cadence near stops to balance precision and battery, and transparently manages large routes. These are tuned via remote config, not in your app.


Best Practices

Error Handling

Wrap every SDK call in try/catch. See Start Tracking for why (invalid keys, denied permissions, etc. surface as thrown errors).

Lifecycle Management

The SDK continues tracking in the background regardless of app state. If you want to observe state changes, use AppState:

import React, { useEffect } from 'react';
import { AppState } from 'react-native';

const DeliveryManager = () => {
useEffect(() => {
const handleAppStateChange = (nextAppState) => {
// handle app state change
};

const subscription = AppState.addEventListener('change', handleAppStateChange);
return () => subscription?.remove();
}, []);

// Your delivery management logic
};

Permission Handling

The RootDoorstepAI component handles permission requests automatically, but you can also handle them manually on Android:

import { PermissionsAndroid, Platform } from 'react-native';

const permissionsToRequest = [
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
PermissionsAndroid.PERMISSIONS.ACTIVITY_RECOGNITION,
];
if (Platform.Version >= 29) {
permissionsToRequest.push(PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION);
}
const granted = await PermissionsAndroid.requestMultiple(permissionsToRequest);

See Permission Issues in the Examples guide for the full version with grant-checking and a Settings fallback prompt.

Next Steps

  1. 💡 View Examples: complete implementation examples