Skip to main content

Notification Customization

This guide covers the configuration of notifications for both background tracking and geofence transitions. On Android, the foreground service requires a persistent notification. On iOS, the system displays a blue status bar indicator instead -- custom notifications are not applicable for tracking.

Platform Behavior​

FeatureAndroidiOS
Tracking notificationPersistent foreground service notification (required)Blue status bar indicator (system-managed)
Geofence notificationsCustomizable via NotificationOptionsCustomizable via NotificationOptions (requires UNUserNotificationCenter)
Action buttonsSupported (up to 3)Not applicable for tracking; not yet supported for geofencing

NotificationOptions Interface​

The NotificationOptions interface is shared across all notification-producing features.

interface NotificationOptions {
enabled?: boolean; // Show notifications (default: true)
title?: string; // Notification title
text?: string; // Notification body text
channelName?: string; // Android notification channel name
channelId?: string; // Custom channel ID
priority?: NotificationPriority; // LOW, DEFAULT, HIGH, MAX
smallIcon?: string; // Android drawable resource name
largeIcon?: string; // Android drawable resource name
color?: string; // Hex color (e.g., "#FF5722")
showTimestamp?: boolean; // Show timestamp on notification
subtext?: string; // Subtext below content
actions?: NotificationAction[]; // Up to 3 action buttons
transitionOverrides?: Partial<Record<
'ENTER' | 'EXIT' | 'DWELL',
Omit<NotificationOptions, 'transitionOverrides' | 'enabled'>
>>; // Per-transition overrides (geofencing only)
}

NotificationPriority​

PriorityBehavior
LOWMinimal notification, no sound or vibration
DEFAULTStandard notification behavior
HIGHMore prominent, may make sound
MAXUrgent notification, heads-up display
import { NotificationPriority } from '@gabriel-sisjr/react-native-background-location';

Tracking Notification (Android)​

The foreground service notification is configured through the notificationOptions field in TrackingOptions.

Setting Defaults at Start​

import {
startTracking,
LocationAccuracy,
NotificationPriority,
} from '@gabriel-sisjr/react-native-background-location';

await startTracking({
accuracy: LocationAccuracy.HIGH_ACCURACY,
updateInterval: 5000,
notificationOptions: {
title: 'Trip in Progress',
text: 'Tracking your location in the background',
priority: NotificationPriority.LOW,
channelName: 'Location Tracking',
color: '#4CAF50',
showTimestamp: true,
smallIcon: 'ic_tracking', // Must exist in res/drawable
largeIcon: 'ic_app_logo', // Must exist in res/drawable
subtext: 'Background tracking active',
},
});

Dynamic Updates​

Update the notification while tracking is active using updateNotification(). This is useful for showing progress, changing the text based on trip state, or updating after a route change.

import { updateNotification } from '@gabriel-sisjr/react-native-background-location';

// Update notification text during a trip
await updateNotification({
title: 'Delivery in Progress',
text: `Stop 3 of 5 - ETA 10 min`,
});

// Update with new priority
await updateNotification({
title: 'Almost There',
text: 'Arriving at destination',
priority: NotificationPriority.HIGH,
});

Only the fields you provide are updated. Fields not specified retain their current values.

Notification Icons​

Runtime Configuration​

Pass drawable resource names (without file extension) to smallIcon and largeIcon.

await startTracking({
notificationOptions: {
smallIcon: 'ic_tracking_small', // res/drawable/ic_tracking_small.png
largeIcon: 'ic_tracking_large', // res/drawable/ic_tracking_large.png
},
});

Static Defaults via AndroidManifest​

You can set default notification icons via <meta-data> in your AndroidManifest.xml instead of passing them at runtime. These are used as fallbacks when no icon is specified in notificationOptions.

<application>
<meta-data
android:name="com.backgroundlocation.notification.small_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="com.backgroundlocation.notification.large_icon"
android:resource="@drawable/ic_notification_large" />
</application>

Icon Resolution Order​

  1. smallIcon / largeIcon from notificationOptions (runtime)
  2. <meta-data> values from AndroidManifest.xml
  3. Convention drawable name (ic_notification)
  4. System default icon

Notification Channel​

Android 8.0+ requires a notification channel. The library creates one automatically.

await startTracking({
notificationOptions: {
channelId: 'my_tracking_channel',
channelName: 'Location Tracking',
priority: NotificationPriority.LOW,
},
});

Important: On Android 8.0+ (API 26), notification channels are immutable after creation. If you change channelId or channelName after the channel already exists on a device, the changes will not take effect for that channel. Use a new channelId or instruct users to clear notification settings.

Notification Action Buttons​

Add up to 3 interactive buttons to the tracking notification.

Configuration​

import type {
NotificationAction,
} from '@gabriel-sisjr/react-native-background-location';

await startTracking({
notificationOptions: {
title: 'Delivery Active',
text: 'En route to destination',
actions: [
{ id: 'stop', label: 'Stop' },
{ id: 'pause', label: 'Pause' },
{ id: 'emergency', label: 'SOS' },
],
},
});

Handling Action Presses​

Use the onNotificationAction callback in useLocationUpdates to react to button presses.

import {
useLocationUpdates,
stopTracking,
} from '@gabriel-sisjr/react-native-background-location';

function TrackingWithActions() {
useLocationUpdates({
onNotificationAction: (event) => {
console.log(`Action pressed: ${event.actionId}`);

switch (event.actionId) {
case 'stop':
stopTracking();
break;
case 'pause':
// Handle pause logic
break;
case 'emergency':
callEmergencyService();
break;
}
},
});

return <TrackingUI />;
}

NotificationAction Interface​

interface NotificationAction {
id: string; // Unique identifier for the action
label: string; // Text displayed on the button
}

NotificationActionEvent​

interface NotificationActionEvent {
tripId: string; // Active trip ID
actionId: string; // ID of the pressed action
}

Geofence Notifications​

Geofence transition notifications support the same NotificationOptions interface with the addition of template variables and transitionOverrides.

Global Configuration​

import { configureGeofenceNotifications } from '@gabriel-sisjr/react-native-background-location';

await configureGeofenceNotifications({
title: '{{transitionType}} -- {{identifier}}',
text: 'Geofence transition at {{latitude}}, {{longitude}}',
channelName: 'Geofence Alerts',
priority: NotificationPriority.HIGH,
color: '#FF5722',
showTimestamp: true,
});

Template Variables​

VariableExampleDescription
{{identifier}}warehouse-northGeofence identifier
{{transitionType}}ENTERENTER, EXIT, or DWELL
{{latitude}}-23.5505Device latitude at transition
{{longitude}}-46.6333Device longitude at transition
{{radius}}200Geofence radius in meters
{{timestamp}}2026-03-25T14:30:00ZISO 8601 timestamp
{{metadata.KEY}}(value)Metadata field from the geofence

Per-Transition Overrides​

Customize notification content per transition type.

await configureGeofenceNotifications({
title: 'Geofence Alert',
text: 'Transition detected',
transitionOverrides: {
ENTER: {
title: 'Entered Zone',
text: 'You entered {{identifier}}',
color: '#4CAF50',
},
EXIT: {
title: 'Left Zone',
text: 'You left {{identifier}}',
color: '#f44336',
},
DWELL: {
title: 'Dwelling',
text: 'You have been at {{identifier}} for a while',
color: '#FF9800',
},
},
});

Per-Geofence Overrides​

Individual geofences can override the global configuration.

import { addGeofence } from '@gabriel-sisjr/react-native-background-location';

// Custom notification for this geofence
await addGeofence({
identifier: 'headquarters',
latitude: 40.7128,
longitude: -74.006,
radius: 500,
notificationOptions: {
title: 'Welcome to HQ!',
text: 'You arrived at {{identifier}}',
},
});

// Suppress notifications for this geofence
await addGeofence({
identifier: 'silent-zone',
latitude: -23.5505,
longitude: -46.6333,
radius: 300,
notificationOptions: false,
});

Hook-Based Configuration​

import { useGeofencing } from '@gabriel-sisjr/react-native-background-location';

const { addGeofence } = useGeofencing({
notificationOptions: {
title: '{{transitionType}} -- {{identifier}}',
text: 'Transition at {{latitude}}, {{longitude}}',
},
});

Note: Geofence notification action buttons (actions field) are not yet supported. This field is available for foreground service notifications only.

iOS Considerations​

Tracking​

iOS does not use a foreground service. The system displays a blue status bar indicator when the app uses background location. There is no way to customize this indicator -- it is entirely system-managed. All notificationOptions for tracking are ignored on iOS.

Geofence Notifications​

iOS geofence notifications use UNUserNotificationCenter. The useLocationPermissions hook requests notification permission as step 3 of its permission flow on iOS.

Without notification authorization, transition events are still detected and delivered to JS callbacks, but no visual notification is shown.

Foreground Display​

By default, iOS does not display notification banners when the app is in the foreground. To show geofence notifications while the app is open, your AppDelegate must implement UNUserNotificationCenterDelegate and allow foreground presentation.

Complete Example​

import React from 'react';
import { View, Text, Button } from 'react-native';
import {
useBackgroundLocation,
useLocationUpdates,
LocationAccuracy,
NotificationPriority,
stopTracking,
} from '@gabriel-sisjr/react-native-background-location';

function NotificationDemo() {
const { startTracking, isTracking } = useBackgroundLocation();

useLocationUpdates({
onNotificationAction: (event) => {
if (event.actionId === 'stop') {
stopTracking();
}
},
});

const handleStart = async () => {
await startTracking(undefined, {
accuracy: LocationAccuracy.HIGH_ACCURACY,
updateInterval: 5000,
notificationOptions: {
title: 'Delivery Active',
text: 'En route to destination',
priority: NotificationPriority.LOW,
channelName: 'Delivery Tracking',
color: '#2196F3',
showTimestamp: true,
subtext: 'Background tracking',
actions: [
{ id: 'stop', label: 'Stop Tracking' },
],
},
});
};

return (
<View>
<Text>Tracking: {isTracking ? 'Active' : 'Inactive'}</Text>
<Button
title={isTracking ? 'Stop' : 'Start with Custom Notification'}
onPress={isTracking ? () => stopTracking() : handleStart}
/>
</View>
);
}

Next Steps​