npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

Readme

nitroping-react-native (React Native SDK)

npm version npm downloads license MIT types

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 nitroping package. 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-native

Peer 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 token

Prefer 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 getDevicePushTokenAsync on purpose. Do not pass getExpoPushTokenAsync output — that ExponentPushToken[...] 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