Firebase Cloud Messaging (FCM) is a messaging solution for sending remote push notifications to Android and iOS devices. react-native-notify-kit ships a first-class integration called FCM Mode that handles the Android / iOS asymmetry for you and is the recommended path for new integrations.
FCM Mode is the recommended approach for FCM push with
react-native-notify-kit. Use the legacy manual pattern at the bottom of this page only if you already have an existing integration and cannot migrate — new integrations should follow FCM Mode.
FCM has two payload shapes and each has a problem:
notificationpayload: the FCM SDK auto-displays on Android. If you also calldisplayNotificationfrom your background handler you get two tray entries, and customdatais routed only to the tapPendingIntentso the library's query APIs can't see it.data-only payload: clean on Android, but iOS treats these as silent pushes and drops 30–60% on real devices.
FCM Mode picks the right payload per platform (data-only on Android, alert + mutable-content: 1 on iOS) but hides the asymmetry behind a single developer API. A Notification Service Extension on iOS reads the shared notifee_options blob and reshapes the notification so you keep full display control while getting APNs reliability.
See FCM Mode for the full architecture, payload schema, migration guide, and troubleshooting.
- An active Firebase project.
@react-native-firebase/appand@react-native-firebase/messaginginstalled and configured.
See the React Native Firebase quick start and the messaging setup guide for the Firebase-side configuration.
The server SDK ships with the main package under the react-native-notify-kit/server subpath export. It has zero runtime dependencies and is meant for Node.js / Firebase Cloud Functions.
// server/sendNotification.ts
import { buildNotifyKitPayload } from 'react-native-notify-kit/server';
import * as admin from 'firebase-admin';
admin.initializeApp();
export async function sendOrderUpdate(deviceToken: string, orderId: string) {
const message = buildNotifyKitPayload({
token: deviceToken,
notification: {
id: `order-${orderId}`,
title: 'Your order is on the way',
body: 'Tap to see live tracking.',
data: { orderId },
android: {
channelId: 'orders',
smallIcon: 'ic_notification',
pressAction: { id: 'open-order', launchActivity: 'default' },
},
ios: {
sound: 'default',
interruptionLevel: 'timeSensitive',
},
},
options: { ttl: 3600 },
});
await admin.messaging().send(message);
}buildNotifyKitPayload returns a Firebase Admin-compatible message that is data-only on Android and alert-style on iOS. Firebase Admin serializes it to the FCM HTTP v1 request format. options.ttl is expressed in seconds; the builder performs the Android millisecond conversion. Both platforms carry an identical notifee_options blob.
handleFcmMessage is a one-liner that parses the server payload, reconstructs a Notification object, and displays it through the usual Notify Kit pipeline.
// index.js
import { AppRegistry } from 'react-native';
import messaging from '@react-native-firebase/messaging';
import notifee, { AndroidImportance } from 'react-native-notify-kit';
import App from './App';
notifee.setFcmConfig({
defaultChannelId: 'default',
defaultPressAction: { id: 'default', launchActivity: 'default' },
});
notifee.createChannel({ id: 'default', name: 'Default', importance: AndroidImportance.HIGH });
notifee.createChannel({ id: 'orders', name: 'Orders', importance: AndroidImportance.HIGH });
messaging().setBackgroundMessageHandler(async remoteMessage => {
await notifee.handleFcmMessage(remoteMessage);
});
AppRegistry.registerComponent('MyApp', () => App);// App.tsx — foreground
import { useEffect } from 'react';
import messaging from '@react-native-firebase/messaging';
import notifee from 'react-native-notify-kit';
export default function App() {
useEffect(() => messaging().onMessage(m => notifee.handleFcmMessage(m)), []);
// ...
}From your project root:
npx react-native-notify-kit init-nseThe CLI patches .pbxproj and Podfile automatically and generates a NotifyKitNSE target using NotifeeExtensionHelper. Supports --dry-run, --force, --target-name, --ios-path, and --bundle-suffix options. Rerun pod install and rebuild.
On iOS, handleFcmMessage is a no-op in background/killed (the NSE has already displayed the notification); in foreground it displays the banner as usual.
For the full reference (server builders, client config, payload schema, migration from the manual pattern, troubleshooting, known limitations) see the FCM Mode guide.
Independent of FCM Mode, you still need device tokens to target specific devices. React Native Firebase's messaging API handles this:
import messaging from '@react-native-firebase/messaging';
async function registerDeviceToken() {
await messaging().registerDeviceForRemoteMessages();
const token = await messaging().getToken();
await postToApi('/users/me/tokens', { token });
}Fetch and update the token on every app boot in case it has changed, and consider listening to onTokenRefresh while the app is open.
This section is retained only for users with an existing integration built on the upstream Notifee manual pattern who cannot migrate right now. New integrations should use FCM Mode instead.
The legacy pattern bypasses FCM Mode's iOS NSE/alert handling, so iOS behavior differs from Android: silent pushes are throttled by APNs (30–60% drop rate is typical), there is no automatic attachment handling, and no foreground customization via NSE. These are inherent trade-offs of the approach and are the reason FCM Mode exists.
The pattern sends a data-only FCM payload with a serialized notification object and calls displayNotification on the client:
// Node.js
await admin.messaging().sendMulticast({
tokens,
data: {
notifee: JSON.stringify({
title: 'Your order has been shipped',
body: 'This message was sent via FCM!',
android: {
channelId: 'default',
pressAction: { id: 'default', launchActivity: 'default' },
},
}),
},
});// React Native
import notifee from 'react-native-notify-kit';
import messaging from '@react-native-firebase/messaging';
function onMessageReceived(message) {
notifee.displayNotification(JSON.parse(message.data.notifee));
}
messaging().onMessage(onMessageReceived);
messaging().setBackgroundMessageHandler(onMessageReceived);Every property in FCM data must be a string — that's why the notification object is JSON-stringified before sending.
If you're maintaining an existing integration like this and want to migrate, see the migration from the manual pattern section of the FCM Mode guide.
- FCM Mode — full guide for the recommended path
- FCM: send messages to specific devices
- FCM: send messages to topics
- FCM: batched messages
