React Native SDK
react-native-notify-sphere on npm. Push notifications, delivery tracking, campaign attribution, and user tags for Android and iOS, built on Firebase Cloud Messaging and Notifee.
Prerequisites#
- React Native 0.70+
- A Firebase project with Cloud Messaging enabled
- A notifySphere account with an App ID and API Token. Grab these from your dashboard after creating an app.
Install#
npm install react-native-notify-sphere
# Peer dependencies (native, required in your app)
npm install @react-native-firebase/app @react-native-firebase/messaging
npm install @notifee/react-native
npm install @react-native-async-storage/async-storage@^1.23.1
npm install react-native-device-info react-native-install-referrer
cd ios && pod install && cd ..The SDK declares these peer dependencies: @react-native-firebase/app and @react-native-firebase/messaging (^22.2.1), @notifee/react-native (^9.1.8), @react-native-async-storage/async-storage (^1.23.1), react-native-device-info (>=10.0.0), and react-native-install-referrer (>=1.0.0).
Android setup#
Add google-services.json
Download
google-services.jsonfrom the Firebase Console and place it atandroid/app/google-services.json.Apply the Google Services plugin
Add the Google Services classpath in
android/build.gradleand apply the plugin as the last line ofandroid/app/build.gradle.Update AndroidManifest.xml
Add the
POST_NOTIFICATIONS,INTERNET, andVIBRATEpermissions, plus the default-icon and default-channelmeta-dataentries.Add a notification icon
Drop an icon at
android/app/src/main/res/drawable/ic_stat_onesignal_default.png. Android silently drops notifications with a missing small icon.
iOS setup#
Add GoogleService-Info.plist
Add
GoogleService-Info.plistfrom the Firebase Console to your Xcode project (all targets, "Copy items if needed").Enable capabilities
In Xcode → Signing & Capabilities, add Push Notifications and Background Modes → Remote notifications.
Configure AppDelegate
Configure Firebase and the notification center delegate in
AppDelegate.mm.
Usage#
1. Register the background handler in index.js#
Register the background handler synchronously, before AppRegistry.registerComponent(). Don't wrap it in a promise or timeout. Otherwise notifications delivered while the app is backgrounded or killed get dropped, because no handler exists yet when the headless JS task starts.
import { AppRegistry } from 'react-native';
import App from './src/App';
import { name as appName } from './app.json';
import NotifySphere from 'react-native-notify-sphere';
import { APP_ID, API_TOKEN } from './src/App';
// Must run synchronously, before registerComponent().
NotifySphere.setBackgroundHandler({
appId: APP_ID,
apiKey: API_TOKEN,
});
AppRegistry.registerComponent(appName, () => App);2. Initialize in App.tsx#
Initialize on mount and listen for notification events.
import { useEffect } from 'react';
import { Platform } from 'react-native';
import NotifySphere from 'react-native-notify-sphere';
export const APP_ID = 'your-notifysphere-app-id';
export const API_TOKEN = 'your-api-token';
const PUSH_TYPE = Platform.OS === 'android' ? 'AndroidPush' : 'IOSPush';
export default function App() {
useEffect(() => {
const init = async () => {
const subscriptionId = await NotifySphere.initialize({
applicationUserId: 123,
type: PUSH_TYPE,
appId: APP_ID,
apiKey: API_TOKEN,
name: 'John Doe',
email: 'john@example.com',
phone: '9876543210',
tags: { userType: 'customer' },
debug: __DEV__,
});
await NotifySphere.updateTags({
applicationUserId: 123,
type: PUSH_TYPE,
tags: { lastLogin: new Date().toISOString() },
});
};
init();
NotifySphere.onNotification((notification, type) => {
// type: 'received' | 'press' | 'opened' | 'initial'
});
return () => NotifySphere.destroy();
}, []);
// ...render your app
}API reference#
initialize(config)#
Registers the device and sets up listeners. Returns Promise<string | undefined>, the server-assigned subscription_id.
| Field | Type | Required | Description |
|---|---|---|---|
applicationUserId | number | Yes | Your internal user ID for this device |
type | string | Yes | 'AndroidPush' or 'IOSPush' |
appId | string | Yes | Your notifySphere App ID |
apiKey | string | Yes | Bearer token from your dashboard |
name / email / phone | string | No | User profile fields (phone as string, to preserve leading zeros) |
tags | Record<string,string> | No | Custom segmentation tags |
debug | boolean | No | Verbose console logs (default false) |
onNotification(callback)#
Registers a callback for all notification events: received, press, opened, initial.
postEvent(params)#
Attributes an in-app conversion (booking, purchase, sign-up) back to the campaign that drove the install or open. Requires initialize() to have run at least once.
await NotifySphere.postEvent({
event: 'booking',
nsClick: 'abc123', // optional, from a campaign deep-link
data: { revenue: 2500, order_id: 'ORD123' },
});updateTags(params)#
Updates user tags without re-registering the device.
setBackgroundHandler(config?)#
Registers the Firebase/Notifee background and terminated-state handler. Must be called synchronously in index.js. Pass appId and apiKey here. They aren't available in a killed-state launch because initialize() hasn't run yet.
destroy()#
Unsubscribes all listeners and resets internal state. Call on logout.
FCM payload format#
Send mixed payloads: a top-level notification block (so the OS auto-displays in background and killed state) plus a data block (for delivery tracking and routing).
{
"notification": { "title": "Hello!", "body": "You have a new message." },
"data": {
"notification_id": "uuid-here",
"sound": "default",
"imageUrl": "https://example.com/image.jpg",
"channelId": "channel_default"
},
"android": { "priority": "high" }
}Troubleshooting#
Delivery receipt works in foreground but not background or killed#
Check two things: your FCM payload must include the top-level notification block (see above), and setBackgroundHandler() must run synchronously at the very top of index.js, never inside a promise or setTimeout.
401 Unauthorized#
Pass apiKey in both initialize() and setBackgroundHandler().
More fixes are in Troubleshooting.
Related#
Stuck or something unclear? Contact us and we'll help.