Implementing Push Notifications (expo-notifications)
1. Requesting Notification Permissions
| Permission | Description | Status |
|---|---|---|
| notifications | Allows the app to receive and display push notifications. | NEW |
Example: Requesting Notification Permissions
import * as Notifications from 'expo-notifications';
// Request permission to show notifications
const { status } = await Notifications.requestPermissionsAsync();
if (status === 'granted') {
console.log("Notification permission granted");
} else {
console.log("Notification permission denied");
}
Note: On iOS, users can revoke permissions at any time from Settings. On Android, permissions are granted by default but can be revoked in app settings.
2. Getting Push Token
| Property | Description | Example |
|---|---|---|
| pushToken | Unique identifier for device to receive push notifications | ExpoPushToken["ExponentPushToken[...]"] |
Example: Request Push Token
import { Notifications } from "expo-notifications";
// Request permissions
await Notifications.requestPermissionsAsync();
// Get push token
const token = await Notifications.getExpoPushTokenAsync();
console.log(token.data);
Note: Push tokens are unique per device and app instance. They expire when the app is uninstalled or permissions are revoked.
3. Scheduling Local Notifications
| Property | Description | Values |
|---|---|---|
| content.title | Title of the notification | string |
| content.body | Body text of the notification | string |
| trigger | Trigger for when the notification should fire | number | Date | { seconds: number; cycle?: 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly'; } |
| identifier | Unique identifier for the notification | string |
| sound | Sound to play when notification fires | true | false | string |
Example: Schedule a local notification after 5 seconds
import * as Notifications from 'expo-notifications';
Notifications.scheduleNotificationAsync({
content: {
title: "Reminder",
body: "Don't forget to complete your task!",
},
trigger: {
seconds: 5,
},
});
Example: Schedule a repeating daily notification
import * as Notifications from 'expo-notifications';
Notifications.scheduleNotificationAsync({
content: {
title: "Daily Reminder",
body: "Time for your daily check-in.",
},
trigger: {
seconds: 0,
cycle: 'daily',
},
});
Note: On Android, local notifications require the
android.permission.POST_NOTIFICATIONS permission to be granted by the user.
4. Handling Received Notifications
| Property | Description | Example |
|---|---|---|
| notification | The received notification object containing data and metadata | { id: '123', title: 'Hello', body: 'This is a test' } |
| data | Custom data payload sent with the notification | { userId: 'user123', action: 'openProfile' } |
| request | Request object that includes the notification and its trigger | { trigger: 'push', content: { ... } } |
Example: Handling Notification in App
import { Notifications } from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async (notification) => {
const { data } = notification.request.content;
console.log('Received notification:', notification);
if (data && data.userId) {
// Navigate to user profile or perform action
return {
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true
};
}
return {
shouldShowAlert: false,
shouldPlaySound: false,
shouldSetBadge: false
};
}
});
Note: The
handleNotification function is called whenever a notification is received while the app is in the foreground or background. It allows you to customize how notifications are handled.
Key Points
- handleNotification is used to define behavior when a notification is received.
- You can control whether an alert, sound, or badge should be shown based on notification content.
- Custom
datacan be used to trigger specific actions in your app.
5. Handling Notification Tap
| Property | Description | Example |
|---|---|---|
| notification | The notification object that was tapped | { title: 'Hello', body: 'This is a tap event' } |
| actionIdentifier | Identifier of the action that triggered the notification | 'DEFAULT' |
Example: Handling Notification Tap
import * as Notifications from 'expo-notifications';
Notifications.addNotificationTapEventListener((notification) => {
console.log('Notification tapped:', notification);
});
// Example notification object
const exampleNotification = {
title: 'Hello',
body: 'This is a tap event',
data: { screen: 'Home' }
};
// Simulated tap handler
console.log('Tapped notification:', exampleNotification);
Note: The tap event listener is only triggered when the app is in the foreground or background. If the app is closed, the notification will be delivered to the system tray.
6. Setting Notification Handler
| Property | Description | Values |
|---|---|---|
| setNotificationHandler | Function to set the notification handler | async (notification) => { ... } |
Example: Setting Notification Handler
import * as Notifications from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async (notification) => {
return {
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
};
},
});
Note: The handler must be set before any notifications are received to ensure proper handling.
7. Setting Badge Count
| Property | Description | Values |
|---|---|---|
| badge | Controls the badge count displayed on the app icon | number or null |
Example: Setting Badge Count
import * as Notifications from 'expo-notifications';
// Set badge count to 5
Notifications.setBadgeCountAsync(5);
// Clear badge count
Notifications.setBadgeCountAsync(null);
Note: Badge count behavior varies by platform. iOS may require additional configuration in
app.json.
8. Canceling Notifications
Canceling notifications in Expo is handled through the Notifications API. You can cancel individual notifications or all pending notifications.
| Method | Description | Notes |
|---|---|---|
| Notifications.cancelScheduledNotificationAsync() | Cancels a specific scheduled notification by ID | Requires the notification ID returned from scheduling |
| Notifications.cancelAllScheduledNotificationsAsync() | Cancels all currently scheduled notifications | Useful for cleaning up before app shutdown or reset |
Example: Canceling a Specific Notification
import * as Notifications from 'expo-notifications';
// Schedule a notification
const notificationId = await Notifications.scheduleNotificationAsync({
content: {
title: 'Scheduled Alert',
body: 'This is a scheduled notification',
},
trigger: {
seconds: 60,
},
});
// Cancel the specific notification
await Notifications.cancelScheduledNotificationAsync(notificationId);
Example: Cancel All Scheduled Notifications
import * as Notifications from 'expo-notifications';
// Cancel all scheduled notifications
await Notifications.cancelAllScheduledNotificationsAsync();
9. Creating Android Channels
| Channel ID | Description | Notes |
|---|---|---|
| default | Default notification channel for the app | Automatically created if not present |
| low_priority | Used for low-priority notifications | May be grouped or suppressed by system |
| high_priority | Used for high-priority notifications | Always shown, even when device is in Do Not Disturb mode |
Example: Creating a Custom Channel
import * as Notifications from 'expo-notifications';
Notifications.createChannelAsync('my-channel', {
name: 'My Custom Channel',
description: 'Used for important notifications',
sound: 'default',
priority: 'high',
vibrate: [200, 100, 200],
});
Note: Channel IDs must be unique within the app and cannot exceed 120 characters.
Warning: On Android 8.0 (API level 26) and above, notification channels are required for all notifications.
10. Customizing Notification Sound
| Property | Values | Description |
|---|---|---|
| sound | string or false |
Sound file to play when notification is received. Can be a filename in the app bundle or false to disable sound. |
Example: Setting Custom Sound
import * as Notifications from 'expo-notifications';
Notifications.setNotificationSoundAsync('custom_sound.mp3');
Note: Sound files must be included in the app bundle and are supported on iOS and Android.
11. Using Rich Notifications
| Property | Values | Description |
|---|---|---|
| title | string |
The title of the notification |
| body | string |
The body text of the notification |
| data | object |
Custom data to pass with the notification |
| sound | boolean | string |
Whether to play a sound or name of sound file |
| badge | number |
Badge count to display on app icon |
| icon | string |
URL or local path to icon image |
| image | string |
URL or local path to image to display in notification |
| channelId | string |
ID of the notification channel (Android) |
Example: Rich Notification with Image
import * as Notifications from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
}),
});
const notification = {
title: 'New Message',
body: 'You have a new message from Alex.',
data: { messageId: '12345' },
sound: true,
badge: 1,
image: 'https://example.com/image.jpg',
};
await Notifications.scheduleNotificationAsync({
content: notification,
trigger: null,
});
Note: On Android, rich notifications require a notification channel to be configured. The
channelId must reference an existing channel created with Notifications.createChannelAsync.
Warning: Image assets must be accessible via a public URL or included in the app bundle. Local file paths are not supported for rich notification images.
12. Grouping Notifications
Grouping notifications allows you to combine multiple notifications into a single grouped notification, which can improve user experience by reducing clutter and providing better organization.
| Property | Description | Values | Notes |
|---|---|---|---|
| groupId | Unique identifier for the group | string |
Required to group notifications together |
| summaryArgument | Summary text for grouped notifications | string |
Used in the summary of grouped notifications |
| groupSummary | Whether to show a group summary | true | false |
Defaults to false |
Example: Creating Grouped Notifications
import * as Notifications from 'expo-notifications';
Notifications.scheduleNotificationAsync({
content: {
title: 'New Message',
body: 'You have a new message',
groupId: 'messages-group',
summaryArgument: '2 new messages',
},
trigger: null,
});
Note: Grouped notifications are supported on both iOS and Android, but behavior may vary depending on the platform's notification center settings.