nitroping-react-native
v0.2.14
Published
React Native SDK for nitroping push notifications — register device tokens (APNs/FCM) and report engagement. Bring your own token source (Firebase, Expo, or bare).
Downloads
245
Maintainers
Readme
nitroping-react-native (React Native SDK)
React Native SDK for nitroping push notifications. Register device tokens (APNs/FCM) and report engagement — with a provider + hooks. Bring your own token source (Firebase, Expo, or bare).
📦 Part of the nitroping-sdk monorepo. Built on the core
nitropingpackage. See the root README for SDKs in other languages.
What this does (and doesn't)
This package is the device-side half of nitroping:
- ✅ Register / refresh a device's push token with nitroping
- ✅ Deactivate a device (e.g. on logout)
- ✅ Report engagement (opened / clicked) when a notification is tapped
- ✅ React
Provider+ hooks for ergonomics
It does not acquire the APNs/FCM token for you, and it does not send
notifications (that's a server concern, done with a secret np_ key). You
acquire the push token however your app already does — then pass it in.
Use a public pk_ key here. Never embed a secret np_ key in an app.
Install
npm install nitroping-react-native
# or
pnpm add nitroping-react-native
# or
yarn add nitroping-react-nativePeer deps: react >= 18, react-native >= 0.74. If you target older RN where
URL is incomplete, also add react-native-url-polyfill
and import it at your app entry.
Quick Start
Wrap your app in a provider with your public key:
import { NitropingProvider } from "nitroping-react-native";
export default function Root() {
return (
<NitropingProvider publicKey="pk_live_...">
<App />
</NitropingProvider>
);
}Register the device token and report taps:
import { useRegisterDevice, useNotificationEvents } from "nitroping-react-native";
function App() {
const token = useFcmToken(); // your token source — see below
const { device, status } = useRegisterDevice({ token, platform: "ios" });
const { reportOpened } = useNotificationEvents();
// in your notification-open handler, once you know the notificationId:
// await reportOpened(notificationId, device!.id)
return; /* ... */
}Token sources (bring your own)
The SDK is agnostic about how you get the push token — pass null until you
have it, then pass the string. The hook re-registers automatically when the
token changes (refresh-safe).
@react-native-firebase/messaging
import messaging from "@react-native-firebase/messaging";
import { useEffect, useState } from "react";
function useFcmToken() {
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
messaging().getToken().then(setToken);
return messaging().onTokenRefresh(setToken);
}, []);
return token;
}expo-notifications
Use the native device token — getDevicePushTokenAsync() — not
getExpoPushTokenAsync(). nitroping delivers through APNs / FCM directly, so
an Expo push token (ExponentPushToken[...]) will look "sent" but never
arrive.
import * as Notifications from "expo-notifications";
const { data: token } = await Notifications.getDevicePushTokenAsync(); // native APNs/FCM tokenPrefer the one-liner below — it handles permission, token, refresh, and opens for you.
Bare PushNotificationIOS
Grab the token from the register event and feed it into useRegisterDevice.
Firebase one-liner (optional)
If you use @react-native-firebase/messaging, the nitroping-react-native/firebase
subpath wires the token fetch, refresh, and notification-open reporting
for you. @react-native-firebase/messaging is an optional peer — install
it only if you use this path.
import messaging from "@react-native-firebase/messaging";
import { useFirebaseRegistration } from "nitroping-react-native/firebase";
function App() {
// Fetches the FCM token, re-registers on refresh, and reports an `opened`
// event when the app is launched from a notification tap.
const { status } = useFirebaseRegistration({
messaging: messaging(),
platform: "android",
});
return; /* ... */
}For tap-tracking to work, send notifications with notification_id +
device_id in the data map. To report opens manually instead, set
autoReportOpens: false and use useNotificationEvents().
Background data messages
Firebase delivers data-only messages to a headless handler registered at the app entry (outside React). Report engagement from there with the plain client:
import messaging from "@react-native-firebase/messaging";
import { NitropingDevice } from "nitroping-react-native";
import { nitropingIdsFromMessage } from "nitroping-react-native/firebase";
const device = new NitropingDevice({ publicKey: "pk_live_..." });
messaging().setBackgroundMessageHandler(async (msg) => {
const ids = nitropingIdsFromMessage(msg);
if (ids) await device.reportEvent({ ...ids, type: "opened" });
});Expo one-liner (optional)
If you use Expo, the nitroping-react-native/expo subpath asks for permission,
fetches the native device token (getDevicePushTokenAsync), re-registers
on refresh, and reports notification opens. expo-notifications is an
optional peer — install it only if you use this path.
import * as Notifications from "expo-notifications";
import { NitropingProvider } from "nitroping-react-native";
import { useExpoRegistration } from "nitroping-react-native/expo";
function Register() {
// Permission → native token → register → refresh → opens. Platform is
// inferred from the token; on iOS the APNs environment (sandbox vs
// production) is set automatically from `__DEV__`.
const { status } = useExpoRegistration({ notifications: Notifications });
return null;
}
export default function App() {
return (
<NitropingProvider publicKey="pk_live_...">
<Register />
{/* ...rest of your app */}
</NitropingProvider>
);
}Native token, not Expo push token. This path uses
getDevicePushTokenAsyncon purpose. Do not passgetExpoPushTokenAsyncoutput — thatExponentPushToken[...]only works with Expo's own push service, and a push to it will look "sent" but never reach the device.
For tap-tracking, send notifications with notification_id + device_id in
the data map (nitroping also echoes nitroping_notification_id /
nitroping_device_id; both are recognised). To report opens manually instead,
pass autoReportOpens: false. If your app requests notification permission
itself, pass requestPermission: false.
API
<NitropingProvider>
Provide a client. Either inline options or a pre-built client:
<NitropingProvider publicKey="pk_..." baseUrl="https://nitroping.dev">
…
</NitropingProvider>useRegisterDevice({ token, platform, userId?, tags?, metadata?, environment?, kind? })
Registers on mount and re-registers when token changes. Returns
{ device, status, error } where status is
"idle" | "registering" | "registered" | "error". Stays idle while token is
null. On iOS, environment ("sandbox" | "production") defaults from
__DEV__ when omitted.
For VoIP / incoming-call pushes, register the PushKit VoIP token (iOS) or
your incoming-call FCM token (Android) as a second device with
kind: "voip" — only "voip" devices receive the server's
delivery: "voip" call pushes:
// Alongside the standard push registration:
useRegisterDevice({ token: voipToken, platform: "ios", kind: "voip" });useExpoRegistration({ notifications, platform?, userId?, tags?, metadata?, requestPermission?, autoReportOpens? })
From nitroping-react-native/expo. Permission + native token + register +
refresh + opens, in one hook. Returns the same shape as useRegisterDevice.
useFirebaseRegistration({ messaging, platform, ... })
From nitroping-react-native/firebase. FCM token + register + refresh +
opens, in one hook.
useNotificationEvents()
Returns { reportOpened(notificationId, deviceId), reportClicked(notificationId, deviceId, actionId?) }.
useNitroping()
Returns the underlying NitropingDevice for imperative use
(registerDevice, deactivateDevice, deactivateDeviceByToken,
reportEvent). Throws if used outside a provider.
On logout, deactivate the device so it stops receiving pushes. Use
deactivateDevice(id) if you kept the id from registerDevice, or
deactivateDeviceByToken(token) when you only have the APNs/FCM token:
const np = useNitroping();
await np.deactivateDeviceByToken(fcmToken); // { id, status: "inactive" }new NitropingDevice({ publicKey, baseUrl?, timeoutMs?, fetch? })
The non-React client, if you don't want hooks.
License
MIT © productdevbook
