Skip to main content

Capacitor SDK Usage & Integration

All 2.2.2 calls use the DoorstepAIDropoffSDK export from @doorstepai/dropoff-sdk-capacitor. The plugin is native-only, so call it after Capacitor boots and guard code that may run during web rendering.

In-SDK Route Geofencing is the recommended way to integrate: hand the SDK your stops and it starts and stops tracking automatically as the driver enters and exits each one. Prefer to drive geofence enter/exit yourself? See Manual Geofencing below.

In-SDK Route Geofencing​

Hand the SDK your stops and it auto-starts and stops a tracking session as the driver enters and exits each one.

This flow has four touchpoints in your driver app (Initialize is shared with the manual flow below):

#When this happens in the driver appWhat you call
1Driver app launchesInitialize
2Start geofencing and tracking all stopsStart Route Geofencing
3Driver confirms drop-off or takes proof of deliveryMark Drop-off
4Stop geofencing and tracking all stopsStop Route Geofencing

If the driver's route changes mid-shift, call Update Stops as well.

Permissions

Request foreground buckets first, then request background/Always location separately. The exact signatures, buckets, states, and staged flow are in Capacitor Permissions.

1. Initialize​

Call init and then setApiKey once during app startup. init configures Android's foreground-service notification and is a no-op on iOS.

import { Capacitor } from '@capacitor/core';
import { DoorstepAIDropoffSDK } from '@doorstepai/dropoff-sdk-capacitor';

export async function initializeDoorstepAI(): Promise<void> {
if (!Capacitor.isNativePlatform()) return;

await DoorstepAIDropoffSDK.init({
notificationTitle: 'Tracking...',
notificationText: 'Tracking your delivery',
});
await DoorstepAIDropoffSDK.setApiKey({ key: 'your-api-key' });

// Restores a persisted route, or does nothing when no route is active.
await DoorstepAIDropoffSDK.resumeRouteGeofencingIfNeeded();
}

Store the API key in secure application configuration. The field passed to setApiKey is named key.

2. Start Route Geofencing​

Call startRouteGeofencing once you have the driver's stops for the shift. Pass every stop up front, not one at a time. ENTER starts a delivery; EXIT stops it only after markDropoff, otherwise timeoutSeconds is the backstop.

import type { DeliveryStop } from '@doorstepai/dropoff-sdk-capacitor';

const stops: DeliveryStop[] = [
{
deliveryId: 'delivery_12345',
address: '123 Main St, San Francisco, CA',
latitude: 37.7749,
longitude: -122.4194,
customerId: 'customer_42',
driverId: 'driver_7',
},
];

await DoorstepAIDropoffSDK.startRouteGeofencing({
stops,
options: {
defaultRadiusMeters: 250,
timeoutSeconds: 1800,
manualForeground: false, // Android only
},
});

const routeListener = await DoorstepAIDropoffSDK.addListener(
'geofenceSessionEvent',
(event) => {
console.log(event.deliveryId, event.type, event.reason);
console.log('Android server id:', event.serverSessionId);
},
);

Each DeliveryStop has deliveryId, address, latitude, longitude, and optional radiusMeters, customerId, and driverId. Each route event has deliveryId, type, and reason; Android STARTED events may also include serverSessionId. Remove the listener when its owner is disposed.

3. Mark Drop-off​

DropoffType is a TypeScript string union, not a runtime enum. Pass 'pod' or 'non_pod' directly. The call is identical for both flows: with In-SDK Route Geofencing, marking drop-off also gates the automatic EXIT stop for that delivery.

await DoorstepAIDropoffSDK.markDropoff({
deliveryId: 'delivery_12345',
dropoffType: 'pod',
});

Custom Events​

await DoorstepAIDropoffSDK.newEvent({
eventName: 'taking_pod',
deliveryId: 'delivery_12345',
timestamp: 1720000000, // optional epoch seconds
});

4. Stop Route Geofencing​

Call stopRouteGeofencing when the shift ends. It clears the route and stops active route sessions:

await DoorstepAIDropoffSDK.stopRouteGeofencing();

Update Stops​

Call updateRouteStops when the driver's route changes mid-shift (a stop added, removed, or reordered). It replaces the stop set without restarting stops that remain:

await DoorstepAIDropoffSDK.updateRouteStops({ stops: updatedStops });

Resuming After Relaunch​

Route state is persisted, but the host still needs to call setApiKey and resumeRouteGeofencingIfNeeded() on every launch to restore it without re-supplying the stop list. It's a no-op if no route is active, so it's safe to call unconditionally — see Initialize above.

Getting Monitored Stops​

getMonitoredStops() resolves to { stops: DeliveryStop[] }, the stops currently registered.

Background route events require locationAlways === 'granted'; see Capacitor Permissions.


Manual Geofencing​

If you'd rather drive geofence enter/exit yourself instead of using In-SDK Route Geofencing above, wire up these four touchpoints:

#When this happens in the driver appWhat you call
1Driver app launchesInitialize
2Driver enters the delivery geofenceStart Tracking
3Driver confirms drop-off or takes proof of deliveryMark Drop-off
4Driver exits the delivery geofenceStop Tracking

1. Initialize​

Initialize the SDK the same way as described in Initialize above. This step is identical for both flows.

2. Start Tracking​

Choose the start method matching the destination data you have. Every Capacitor method receives one options object.

startDeliveryByAddress is an exact alias for startDeliveryByAddressType; both accept StartDeliveryByAddressOptions.

import {
DoorstepAIDropoffSDK,
type AddressType,
} from '@doorstepai/dropoff-sdk-capacitor';

const byPlace = await DoorstepAIDropoffSDK.startDeliveryByPlaceID({
placeID: 'some_place_id',
deliveryId: 'delivery_12345',
timeoutSeconds: 1800,
customerId: 'customer_42',
driverId: 'driver_7',
});

const address: AddressType = {
streetNumber: '123',
route: 'Main Street',
subPremise: 'Apt 4B',
locality: 'San Francisco',
administrativeAreaLevel1: 'CA',
postalCode: '94102',
};

await DoorstepAIDropoffSDK.startDeliveryByAddress({
address,
deliveryId: 'delivery_12345',
coordinates: { lat: 37.7749, lng: -122.4194 },
manualForeground: false, // Android only
});

await DoorstepAIDropoffSDK.startDeliveryByAddressString({
address: '123 Main St, Apt 4B, San Francisco, CA 94102',
deliveryId: 'delivery_12345',
});

Every start resolves to { serverSessionId?: string }. Android includes the server id when the call creates a network-backed session. On iOS it arrives asynchronously through the sessionServerIdAssigned listener:

const idListener = await DoorstepAIDropoffSDK.addListener(
'sessionServerIdAssigned',
({ deliveryId, serverSessionId }) => {
console.log(deliveryId, serverSessionId);
},
);

// Later, when the listener's owner is disposed:
await idListener.remove();

Shared optional start fields are timeoutSeconds, customerId, and driverId. Address-based methods also accept coordinates; supported Android starts accept manualForeground. startDeliveryByPlusCode and startDeliveryByLatLng remain for compatibility but are deprecated. On Android, those two legacy starts do not support manualForeground.

3. Mark Drop-off​

Mark the drop-off the same way as described in Mark Drop-off above. This step is identical for both flows.

4. Stop Tracking​

await DoorstepAIDropoffSDK.stopDelivery({
deliveryId: 'delivery_12345',
});

Framework notes​

  • Guard calls with Capacitor.isNativePlatform() when code may run on the web or during SSR.
  • Next.js calls belong in 'use client' modules after mount.
  • Angular and Vue calls belong in their post-bootstrap lifecycle hooks.
  • Rebuild and run npx cap sync whenever changed web code must ship in the native shell.
  • Wrap SDK calls in try/catch; bad input, denied permissions, and native failures reject their promises.
  • removeAllListeners() removes both DoorstepAI listener types at once; prefer each handle's remove() method when ownership is scoped to a component.

Next steps​

  1. Review permissions
  2. See complete examples
  3. Review installation and native declarations