Advanced Push & Local Notifications in React Native with Firebase and Notifee (Part 2)
StackQuill
Advanced Push & Local Notifications in React Native with Firebase and Notifee (Part 2)
In the first part of this series, we built a complete Firebase Cloud Messaging (FCM) setup for React Native using Firebase and Notifee.
Now, in Part 2, we’ll go deeper and explore:
- 📱 Local notifications
- ✨ Custom notification styles
- ⏰ Triggers and scheduling
- ⚡ Action buttons and backend integration
- 🎧 Media and chat-style notifications
- 📊 Event tracking for every app state (Foreground, Background, Killed)
This part focuses on building a robust notification system that behaves consistently across app states — with fixes to ensure reliable delivery and accurate navigation.
📱 1. Local Notifications with Notifee
Local notifications are shown without FCM, usually triggered by in-app events — such as reminders or task completions.
jsimport notifee, { AndroidImportance, TriggerType } from '@notifee/react-native'; // Simple local notification async function showLocalNotification() { await notifee.requestPermission(); const channelId = await notifee.createChannel({ id: 'local', name: 'Local Notifications', importance: AndroidImportance.HIGH, }); await notifee.displayNotification({ title: 'NotifyMeApp Reminder', body: 'Your scheduled task is ready!', android: { channelId, smallIcon: 'ic_launcher', }, }); }
You can call showLocalNotification() anywhere — even as a response to user actions or events.
⏰ 2. Notification Triggers
Notifee allows scheduled or event-based notifications.
Example: Trigger after 10 seconds
jsconst trigger = { type: TriggerType.TIMESTAMP, timestamp: Date.now() + 10 * 1000, // 10 seconds later }; await notifee.createTriggerNotification( { title: 'NotifyMeApp', body: '⏰ Scheduled notification fired!', android: { channelId: 'local' }, }, trigger );
Example: Repeat daily reminder
jsconst trigger = { type: TriggerType.INTERVAL, interval: 24 * 60 * 60, // every 24 hours }; await notifee.createTriggerNotification( { title: 'Daily Reminder', body: 'It’s time to check new updates!', android: { channelId: 'local' }, }, trigger );
🧱 3. Customizing Notifications
You can completely customize your notification look using Notifee’s Android styles.
Big Picture Style (with Image)
jsawait notifee.displayNotification({ title: 'New Offer Available 🎉', body: 'Get 20% off on your next rental!', android: { channelId: 'promo', style: { type: notifee.AndroidStyle.BIGPICTURE, picture: 'https://example.com/offer-banner.jpg', }, }, });
Messaging Style (for Chat)
jsawait notifee.displayNotification({ title: 'John Doe', body: 'Hey! Are you available for the shoot tomorrow?', android: { channelId: 'chat', style: { type: notifee.AndroidStyle.MESSAGING, person: { name: 'John Doe' }, messages: [ { text: 'Hey! Are you available for the shoot tomorrow?', timestamp: Date.now() }, ], }, }, });
⚙️ 4. Notification Actions (with Backend Support)
Add buttons directly to your notifications to trigger specific actions.
js<!-- AndroidManifest.xml --> <activity android:name=".MainActivity"> <intent-filter> <action android:name="OPEN_ACTIVITY_1" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
Then in your notification payload (from backend):
jsconst message = { token, notification: { title: 'NotifyMeApp', body: 'New message received', }, android: { channelId: 'chat', actions: [ { title: 'Reply', pressAction: { id: 'OPEN_ACTIVITY_1', }, }, ], }, };
In your app:
jsnotifee.onForegroundEvent(({ type, detail }) => { if (type === notifee.EventType.ACTION_PRESS && detail.pressAction.id === 'OPEN_ACTIVITY_1') { console.log('User tapped Reply button'); // Backend can be notified here (e.g., mark as read or open chat) } });
🧠 5. Notification Events Across App States
Recent improvements have made notifications behave consistently across all app states. Here’s how you can handle each transition cleanly 👇
| Received In | Opened From | Expected Behavior |
|---|---|---|
| Foreground | Foreground | Show custom in-app popup or Notifee local notification |
| Foreground | Background | Navigate to target screen after resume |
| Foreground | Killed | Use getInitialNotification() to handle navigation |
| Background | Foreground | Auto-navigate to notification target |
| Background | Background | Open directly to target screen |
| Background | Killed | Retrieve data from FCM launch event |
| Killed | Foreground | Fetch from last FCM message using onNotificationOpenedApp |
| Killed | Background | Same as above — delayed navigation allowed |
| Killed | Killed | Delivered silently; handle upon next app launch |
Implementation Example
jsimport messaging from '@react-native-firebase/messaging'; import notifee from '@notifee/react-native'; import { navigationRef } from './NavigationService'; // Foreground messages messaging().onMessage(async (remoteMessage) => { await notifee.displayNotification({ title: remoteMessage.notification?.title, body: remoteMessage.notification?.body, android: { channelId: 'default' }, }); }); // When app is opened from background messaging().onNotificationOpenedApp((remoteMessage) => { const screen = remoteMessage.data?.targetScreen; if (screen) navigationRef.current?.navigate(screen); }); // When app is launched from a killed state messaging() .getInitialNotification() .then((remoteMessage) => { if (remoteMessage) { const screen = remoteMessage.data?.targetScreen; if (screen) navigationRef.current?.navigate(screen); } });
🎧 6. Media & Chat Notifications
To include images, videos, or chat previews inside notifications:
jsawait notifee.displayNotification({ title: '🎬 Video Upload Complete!', body: 'Your project is now ready to share.', android: { channelId: 'media', style: { type: notifee.AndroidStyle.BIGPICTURE, picture: 'https://example.com/video-thumbnail.jpg', }, }, });
For chat-like experience:
jsawait notifee.displayNotification({ title: 'Anna', body: 'Hey! New project details are ready!', android: { channelId: 'chat', style: { type: notifee.AndroidStyle.MESSAGING, person: { name: 'Anna' }, messages: [ { text: 'Hey! New project details are ready!', timestamp: Date.now() }, { text: 'Let’s discuss soon.', timestamp: Date.now() }, ], }, }, });
✅ Key Fixes and Improvements
In the latest implementation:
- Notifications tapped from a killed state now navigate correctly.
- Foreground notifications no longer duplicate when both FCM and Notifee handlers are active.
- Deep links from background notifications navigate smoothly on resume.
Resolved by:
- Using
getInitialNotification()for cold starts - Ensuring single Notifee channel creation
- Separating local + FCM handlers
- Maintaining event order for consistent navigation
🎯 Wrapping Up
In this advanced guide, we covered:
- Local & scheduled notifications
- Trigger-based alerts
- Media and chat-style notifications
- Custom action buttons integrated with backend
- Complete event handling across all app states
Together with Part 1, you now have a production-ready notification system for any React Native app.
Related Articles
From Learning to Implementation: My Journey with Firebase Analytics & GA4
Over the past few weeks, I've been focused on deepening my understanding of mobile analytics—not just...
Mastering GA4 for Mobile Apps — From Events to Business Insights
Integrating Firebase Analytics is an excellent first step toward understanding how users interact...
Firebase Analytics in React Native — Complete Implementation Guide
Analytics is one of the most valuable tools you can add to a mobile application. While building...