React Native Push Notifications
Push notifications reach users even when the app is closed. A server sends a message to Apple's or Google's notification services, which deliver it to the user's device. React Native handles both local notifications (triggered by the app itself) and remote push notifications (sent from a server).
How Push Notifications Work
Your Server
│
│ sends notification payload
▼
APNs (Apple) or FCM (Google/Firebase)
│
│ routes to the right device
▼
User's Phone
│
│ system delivers the notification
▼
┌─────────────────────────────────┐
│ 🔔 My App │
│ Your order has shipped! │
│ Tap to track delivery. │
└─────────────────────────────────┘
Installing the Notification Library
npx expo install expo-notifications expo-device
Step 1 — Request Permission
You must ask the user for permission before sending any notification. iOS always shows a system dialog. Android 13+ also requires permission.
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
async function requestNotificationPermission() {
if (!Device.isDevice) {
alert('Push notifications only work on physical devices.');
return false;
}
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Notification permission denied.');
return false;
}
return true;
}
Step 2 — Get the Expo Push Token
The push token is a unique address for this specific app on this specific device. Your server uses it to send notifications to the right phone.
async function getPushToken() {
const granted = await requestNotificationPermission();
if (!granted) return null;
const token = await Notifications.getExpoPushTokenAsync({
projectId: 'your-expo-project-id', // from app.json
});
console.log('Push Token:', token.data);
// Looks like: ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]
// Save this to your server for the logged-in user
await savePushTokenToServer(token.data);
return token.data;
}
Push Token Flow: ┌──────────────────────────────────────────┐ │ App requests token from Expo service │ │ ↓ │ │ Expo service returns unique token string │ │ ↓ │ │ App sends token to YOUR server │ │ ↓ │ │ Server stores token with user account │ │ ↓ │ │ Later: server uses token to send message │ └──────────────────────────────────────────┘
Step 3 — Configure Notification Behaviour
Set how notifications appear when the app is in the foreground (open and active).
// Add this at the top of App.js, outside any component
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true, // show the banner
shouldPlaySound: true, // play the sound
shouldSetBadge: true, // update the badge count on app icon
}),
});
Local Notifications
Local notifications are triggered by the app itself — no server needed. Use them for reminders, alarms, or offline alerts.
// Schedule a notification 5 seconds from now
async function sendLocalNotification() {
await Notifications.scheduleNotificationAsync({
content: {
title: '⏰ Reminder',
body: 'Your meeting starts in 5 minutes.',
data: { screen: 'Calendar' }, // extra data to use when tapped
},
trigger: {
seconds: 300, // 300 seconds = 5 minutes
},
});
}
// Schedule at a specific time
await Notifications.scheduleNotificationAsync({
content: { title: 'Good Morning!', body: 'Time for your workout.' },
trigger: {
hour: 7,
minute: 30,
repeats: true, // every day at 7:30 AM
},
});
Listening to Notification Events
Your app needs to respond when a notification arrives or when the user taps one.
import { useEffect, useRef } from 'react';
export default function App() {
const notificationListener = useRef();
const responseListener = useRef();
useEffect(() => {
// Fires when a notification arrives while app is open
notificationListener.current = Notifications.addNotificationReceivedListener(
(notification) => {
console.log('Notification received:', notification.request.content.title);
}
);
// Fires when the user taps the notification
responseListener.current = Notifications.addNotificationResponseReceivedListener(
(response) => {
const { screen } = response.notification.request.content.data;
if (screen) {
navigation.navigate(screen); // navigate to the relevant screen
}
}
);
return () => {
Notifications.removeNotificationSubscription(notificationListener.current);
Notifications.removeNotificationSubscription(responseListener.current);
};
}, []);
}
Notification states: App is OPEN → addNotificationReceivedListener fires App is CLOSED → system shows notification banner User TAPS it → app opens + addNotificationResponseReceivedListener fires
Sending Remote Push Notifications via Expo
Use the Expo Push Notification service to send notifications from your server without configuring APNs or FCM directly.
// From your server (Node.js example)
const message = {
to: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]',
sound: 'default',
title: '📦 Order Update',
body: 'Your order #1234 has shipped!',
data: { orderId: '1234', screen: 'OrderDetail' },
};
await fetch('https://exp.host/--/api/v2/push/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message),
});
Managing the Badge Count
// Set the badge number on the app icon await Notifications.setBadgeCountAsync(5); // shows "5" on app icon // Clear the badge when user opens the app await Notifications.setBadgeCountAsync(0);
App icon states: ┌─────┐ ┌─────┐ │ App │ │ App │⁵ │ │ │ │ └─────┘ └─────┘ No badge Badge = 5 unread
Cancelling Scheduled Notifications
// Cancel a specific scheduled notification by its ID
const id = await Notifications.scheduleNotificationAsync({ ... });
await Notifications.cancelScheduledNotificationAsync(id);
// Cancel all scheduled notifications
await Notifications.cancelAllScheduledNotificationsAsync();
Summary
Push notifications require a unique push token per device. Request permission first, then get the token and save it to your server. Use setNotificationHandler to control foreground behaviour. Local notifications are scheduled within the app — no server needed. Remote notifications come from your server through Expo's push service. Listen to notification taps to navigate users to the right screen.
