expo-notifications
Version: 55.0.7
Provides an API to fetch push notification tokens and to present, schedule, receive, and respond to notifications. Supports both local and remote push notifications.
Installation
npx expo install expo-notifications
Usage
import * as Notifications from 'expo-notifications';
// Configure notification behavior
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
// Request permissions
const { status } = await Notifications.requestPermissionsAsync();
// Get push token
const token = (await Notifications.getExpoPushTokenAsync()).data;
// Schedule local notification
await Notifications.scheduleNotificationAsync({
content: {
title: 'Hello!',
body: 'This is a notification',
},
trigger: {
seconds: 5,
},
});
// Listen for notifications
Notifications.addNotificationReceivedListener((notification) => {
console.log('Notification received:', notification);
});
Notifications.addNotificationResponseReceivedListener((response) => {
console.log('Notification tapped:', response);
});
API Reference
Permissions
requestPermissionsAsync(request)
(request?: NotificationPermissionsRequest) => Promise<NotificationPermissionsStatus>
Requests notification permissionsconst { status } = await Notifications.requestPermissionsAsync({
ios: {
allowAlert: true,
allowBadge: true,
allowSound: true,
},
});
getPermissionsAsync()
() => Promise<NotificationPermissionsStatus>
Gets current permission status
Push Tokens
getExpoPushTokenAsync(options)
(options?: ExpoPushTokenOptions) => Promise<ExpoPushToken>
Gets Expo push tokenconst token = await Notifications.getExpoPushTokenAsync({
projectId: 'your-project-id',
});
console.log('Token:', token.data);
getDevicePushTokenAsync()
() => Promise<DevicePushToken>
Gets native device push token (FCM/APNs)
Local Notifications
scheduleNotificationAsync(request)
(request: NotificationRequestInput) => Promise<string>
Schedules a local notificationconst id = await Notifications.scheduleNotificationAsync({
content: {
title: 'Reminder',
body: 'Don\'t forget!',
data: { customData: 'value' },
},
trigger: {
seconds: 10,
},
});
presentNotificationAsync(content)
(content: NotificationContentInput) => Promise<string>
Shows notification immediatelyawait Notifications.presentNotificationAsync({
title: 'Now',
body: 'Immediate notification',
});
cancelScheduledNotificationAsync(identifier)
(identifier: string) => Promise<void>
Cancels scheduled notification
cancelAllScheduledNotificationsAsync()
Cancels all scheduled notifications
getAllScheduledNotificationsAsync()
() => Promise<Notification[]>
Gets all scheduled notifications
Notification Management
dismissNotificationAsync(identifier)
(identifier: string) => Promise<void>
Dismisses displayed notification
dismissAllNotificationsAsync()
Dismisses all displayed notifications
getPresentedNotificationsAsync()
() => Promise<Notification[]>
Gets currently displayed notifications
Badge Count
setBadgeCountAsync(count)
(count: number) => Promise<boolean>
Sets app badge countawait Notifications.setBadgeCountAsync(5);
Event Listeners
addNotificationReceivedListener(listener)
(listener: (notification: Notification) => void) => Subscription
Listens for received notificationsconst subscription = Notifications.addNotificationReceivedListener(
(notification) => {
console.log('Received:', notification.request.content.title);
}
);
addNotificationResponseReceivedListener(listener)
(listener: (response: NotificationResponse) => void) => Subscription
Listens for notification tapsNotifications.addNotificationResponseReceivedListener((response) => {
const data = response.notification.request.content.data;
// Navigate based on data
});
Configuration
setNotificationHandler(handler)
(handler: NotificationHandler | null) => void
Configures notification behaviorNotifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
priority: Notifications.AndroidNotificationPriority.HIGH,
}),
});
setNotificationChannelAsync(identifier, channel)
(identifier: string, channel: NotificationChannel) => Promise<NotificationChannel | null>
Creates/updates Android notification channelawait Notifications.setNotificationChannelAsync('default', {
name: 'Default',
importance: Notifications.AndroidImportance.HIGH,
vibrationPattern: [0, 250, 250, 250],
sound: 'notification.wav',
});
Examples
Complete Setup
import * as Notifications from 'expo-notifications';
import { useState, useEffect, useRef } from 'react';
import { Platform } from 'react-native';
// Configure handler
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
export default function App() {
const [pushToken, setPushToken] = useState('');
const notificationListener = useRef<Notifications.Subscription>();
const responseListener = useRef<Notifications.Subscription>();
useEffect(() => {
registerForPushNotifications();
// Add listeners
notificationListener.current = Notifications.addNotificationReceivedListener(
(notification) => {
console.log('Notification received:', notification);
}
);
responseListener.current = Notifications.addNotificationResponseReceivedListener(
(response) => {
console.log('Notification tapped:', response);
}
);
return () => {
notificationListener.current?.remove();
responseListener.current?.remove();
};
}, []);
async function registerForPushNotifications() {
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Failed to get push token');
return;
}
const token = (await Notifications.getExpoPushTokenAsync()).data;
setPushToken(token);
// Send token to your server
await sendTokenToServer(token);
// Android channel
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
});
}
}
// Rest of component...
}
Schedule Notification
import * as Notifications from 'expo-notifications';
async function scheduleReminder() {
await Notifications.scheduleNotificationAsync({
content: {
title: 'Reminder',
body: 'Time to check your tasks',
data: { screen: 'tasks' },
},
trigger: {
hour: 9,
minute: 0,
repeats: true,
},
});
}
Handle Notification Tap
import * as Notifications from 'expo-notifications';
import { useNavigation } from '@react-navigation/native';
function useNotifications() {
const navigation = useNavigation();
useEffect(() => {
const subscription = Notifications.addNotificationResponseReceivedListener(
(response) => {
const { screen } = response.notification.request.content.data;
if (screen) {
navigation.navigate(screen as never);
}
}
);
return () => subscription.remove();
}, []);
}
| Platform | Supported |
|---|
| iOS | ✅ |
| Android | ✅ |
| Web | ✅ (Limited) |
Configuration
app.json
{
"expo": {
"plugins": [
[
"expo-notifications",
{
"icon": "./assets/notification-icon.png",
"color": "#ffffff",
"sounds": ["./assets/notification.wav"]
}
]
],
"notification": {
"icon": "./assets/notification-icon.png",
"color": "#ffffff"
}
}
}
Permissions
iOS: Add to app.json:
{
"ios": {
"infoPlist": {
"UIBackgroundModes": ["remote-notification"]
}
}
}
Android: Permissions automatically added.
Best Practices
- Request Permissions: Always request before sending notifications
- Configure Handler: Set notification handler before listeners
- Clean Up: Remove listeners in component cleanup
- Android Channels: Create channels for Android 8+
- Error Handling: Handle permission denials gracefully
On iOS, notifications may not appear when app is in foreground unless configured in notification handler.
Resources