Docs Add PusherHub to your app
React Native push notifications: add the SDK step by step
Android and iOS, with Expo too — every step with a picture from a real React Native app: the SDK file, the packages, Gradle, the Podfile, Xcode and the code in App.tsx.
12 min read
All guides
- Get started with PusherHub
- Create a Firebase project
- Get your Firebase service account file
- Find your Sender ID
- iOS push notifications: add your Apple push key to Firebase
- Add push notifications to your app
- Flutter
- Android (Kotlin)
- Java
- React Native
- iOS (Swift)
- Unity
- Send a test push notification
- Send your first push notification
Download PusherHub.js
In the dashboard, open
Applications
your app
SDK Integration
and pick React Native ①. Choose where your app runs — Android + iOS ② here — and click Download PusherHub.js ③. It goes in your src/ folder ④.
Every step below is on this tab too, with your own keys already filled in — copy the code from there.
Put the three files in your project
PusherHub.js① goes insrc/(make the folder if you don't have one).- Android:
google-services.json② goes inandroid/app/. - iOS:
GoogleService-Info.plist③ goes in your app's folder underios/, and Xcode has to know about it: openios/MyApp.xcworkspace(your app's name), drag the file onto your app's folder and tick your app target.
Install the packages
Run this in your project folder ③. It adds Firebase Cloud Messaging ①, plus what PusherHub uses to ask for permission and show notifications (notifee), to remember the phone (async-storage) and to show web in-app messages ② (webview — skip it if you don't use those).
npm install @react-native-firebase/app @react-native-firebase/messaging \
@react-native-async-storage/async-storage @notifee/react-native \
react-native-webview
For iOS, cd ios && pod install ④ comes after the Podfile change in step 7. Using Expo? Install with npx expo install instead of npm install.
Android: add the Google services plugin
Open android/build.gradle. Inside buildscript { dependencies { } }, add ①:
classpath("com.google.gms:google-services:4.4.3")
Android: turn the plugin on for the app
Open android/app/build.gradle and add this under the other apply plugin lines at the top ①:
apply plugin: "com.google.gms.google-services"
Android: add to AndroidManifest.xml
Open android/app/src/main/AndroidManifest.xml and add to the manifest you already have — don't replace it:
- The permissions ①.
- A second
<intent-filter>② inside theMainActivity<activity>. Without it, tapping a notification while the app is closed doesn't open it. The name says Flutter, but every PusherHub notification uses it, React Native apps too.
iOS: Podfile and pod install
Firebase for iOS needs dynamic frameworks. In ios/Podfile, inside your app's target … do block, add ①:
use_frameworks! :linkage => :dynamic
Then run cd ios && pod install. Without the line, pod install fails.
iOS: start Firebase in AppDelegate.swift
Open your app's AppDelegate.swift under ios/ and add the import ① and FirebaseApp.configure() as the first line of application(_:didFinishLaunchingWithOptions:) ②.
An Objective-C AppDelegate.mm takes #import <Firebase.h> and [FIRApp configure]; instead.
iOS: turn on push notifications in Xcode
Open ios/MyApp.xcworkspace in Xcode and select your app target (called Runner in the picture). On Signing & Capabilities ①, choose your paid Apple Developer Team, then click + Capability ② and add Background Modes — tick Remote notifications ③ — and Push Notifications ④.
iOS with Expo: app.json instead
Expo makes the ios/ folder from app.json, so hand edits to Xcode, the Podfile or the AppDelegate would be lost. In an Expo app, do this instead of steps 7–9:
- In
"ios": your bundle ID, the Firebase file (putGoogleService-Info.plistin the project folder) and your Apple Team ID ①. - The push entitlement and background notifications ②.
- The plugins ③: the two Firebase ones, and
expo-build-propertiesfor dynamic frameworks.
Then build a development build — Expo Go can't receive pushes:
npx expo install expo-build-properties npx expo prebuild --platform ios npx expo run:ios --device
iOS: show pictures in notifications (recommended)
An iPhone doesn't download a notification's image by itself when the app is closed — without this step it shows only the title and text. In Xcode, with your .xcworkspace open:
-
File
New
Target…
, pick Notification Service Extension, name it
NotificationService, click Finish, then Don't Activate. - Replace everything in
ios/NotificationService/NotificationService.swiftwith the file on your SDK Integration tab.
Expo apps need a config plugin for this, so skip it there for now. The simulator can't draw notification pictures, so check this on a real iPhone.
Attach PusherHub in index.js
Open index.js and add the import ① and PusherHub.attachNotificationHandlers() ② — before AppRegistry.registerComponent, not inside a component, so it's ready before the app finishes opening.
Expo: put the same line in index.ts (or index.js), just before registerRootComponent(App).
Start PusherHub in App.tsx
Open App.tsx and add the code from your SDK Integration tab — your keys and server are already filled in. (In the picture they're placeholders.)
- The import ①.
PusherHub.initialize(…)② in auseEffect, with your App key, Public key and server.registerDevice()③ asks the user to allow notifications, gets the push token and adds the phone to PusherHub.collectDeviceMetadata()after it is optional: it adds the phone's brand, model, language and country.<PusherHubMessageHost>④ around your app — optional: it shows your in-app messages when the app opens. Leave it out if you only send notifications.
Optional: log the user in
If your app has its own sign-in, tell PusherHub who's using the phone. Then you can send to one person by your own user ID. It's remembered, even after the app restarts, until logout().
// When someone signs in: await PusherHub.login(currentUserId); // When they sign out: await PusherHub.logout();
Optional: open a screen when a notification is tapped
Put your own data in Custom Data when you create a notification — say {"campaign_id": "232"} — and your app gets it back whenever someone taps that notification, whether it was open, in the background or closed. Add onNotificationOpened to the PusherHub.initialize(…) in App.tsx from step 13:
export const navigationRef = createNavigationContainerRef(); // <NavigationContainer ref={navigationRef} onReady={openPending}>
let pendingCampaignId = null;
const openPending = () => {
if (pendingCampaignId) navigationRef.navigate('Campaign', { id: pendingCampaignId });
pendingCampaignId = null;
};
await PusherHub.initialize({
appKey: 'YOUR_APP_KEY',
publicKey: 'YOUR_PUBLIC_KEY',
baseUrl: 'YOUR_SERVER',
onNotificationOpened: (data) => {
if (!data.campaign_id) return;
pendingCampaignId = data.campaign_id;
if (navigationRef.isReady()) openPending();
},
});
A tap that opened a closed app can arrive before your navigation is ready — pendingCampaignId keeps it until it is. Every value arrives as text ("232"). This needs PusherHub.js from 24 October 2026 or later — download it again if yours is older.
Run the app on a phone
Run npx react-native run-android on an Android phone or emulator with Google Play, or npx react-native run-ios --device on a real iPhone (the iOS simulator can't get push notifications). Tap Allow when it asks about notifications. Within a few seconds the phone shows up in PusherHub under Devices.