Handle notifications

The snippets below show the smallest possible handler — just enough to illustrate which fields to read and where the Stream payload lives in each library. Production apps need to add permission requests, channel setup, background handling and tap navigation. See the platform-specific guides for the full setup.

Use @react-native-firebase/messaging to receive FCM messages on Android and @react-native-community/push-notification-ios to handle taps on iOS. Display the local notification with @notifee/react-native on Android (iOS renders the banner natively from aps.alert).

Notifications displaying

On Android, Stream sends data-only FCM messages, so the OS doesn't render anything on its own. Register both a background and a foreground handler — setBackgroundMessageHandler covers killed state, onMessage covers foreground:

import { isFirebaseStreamVideoMessage } from "@stream-io/video-react-native-sdk";
import messaging from "@react-native-firebase/messaging";
import notifee from "@notifee/react-native";

async function displayStreamNotification(data: any) {
  if (data?.sender !== "stream.video" || data?.type === "call.ring") return;

  await notifee.displayNotification({
    title: "Call notification",
    body: `${data.created_by_display_name ?? "Someone"} is notifying you about a call`,
    data: { call_cid: data.call_cid, type: data.type, sender: "stream.video" },
    android: { channelId: "stream_non_ringing_calls" },
  });
}

// Background / killed state — must be registered at module init.
messaging().setBackgroundMessageHandler(async (msg) => {
  if (isFirebaseStreamVideoMessage(msg)) {
    await displayStreamNotification(msg.data);
  }
});

// Foreground
messaging().onMessage(async (msg) => {
  if (isFirebaseStreamVideoMessage(msg)) {
    await displayStreamNotification(msg.data);
  }
});

Interaction handling

Notifee surfaces taps for notifications it displayed. Register foreground / background event handlers plus a cold-start check:

import notifee, { EventType } from "@notifee/react-native";

function handleTap(data: any) {
  if (data?.sender !== "stream.video") return;
  // data.type, data.call_cid are available here.
  // Navigate to the call screen using your navigation method.
}

notifee.onForegroundEvent(({ type, detail }) => {
  if (type === EventType.PRESS) handleTap(detail.notification?.data);
});

notifee.onBackgroundEvent(async ({ type, detail }) => {
  if (type === EventType.PRESS) handleTap(detail.notification?.data);
});

For the full list of fields available on the Stream payload (data on Android, stream on iOS), see the Payload shape section in the overview.