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

@notibase/react-native

v0.5.0

Published

Notibase for React Native and Expo — push notifications, an in-app inbox and attribution, with no native modules of its own

Readme


Pure TypeScript. Nothing to link, no pods, no Gradle, and no config plugin — so it works in Expo Go, in a development build, and in bare React Native without a prebuild. You keep the push library you already have and hand us the token.

Coming from OneSignal, or straight from Firebase

Notibase is an alternative to OneSignal, and the device-side model is the same shape: register a token, identify the person behind it, tag them, send to a segment. Most of a port is renaming calls. What is arranged differently is that push, an in-app inbox, email and SMS are one audience and one API here rather than several products with separate lists.

It is not an alternative to Firebase Cloud Messaging and does not try to be. You keep FCM and hand us the token: FCM delivers, Notibase decides who to deliver to — then carries the same campaign to iOS, the web, an inbox, an email and a text without you writing any of it a second time.

Install

npm install @notibase/react-native
# Recommended — without it, the device is only remembered until the app closes:
npx expo install @react-native-async-storage/async-storage

Quick start

import { Notibase } from "@notibase/react-native";

await Notibase.configure("ck_live_…");   // publishable by design

Then hand it your push token. Which call you use matters, and this is the one thing worth reading twice:

// Expo — the DEVICE token, not the Expo push token.
import * as Notifications from "expo-notifications";
const { data } = await Notifications.getDevicePushTokenAsync();
await Notibase.registerPushToken(data);

// @react-native-firebase/messaging — note the source.
import messaging from "@react-native-firebase/messaging";
const token = await messaging().getToken();
await Notibase.registerPushToken(token, { source: "firebase" });

getExpoPushTokenAsync() returns a token only Expo's own push service can deliver to, so registering one produces a device that can never receive anything. The SDK refuses it by name rather than letting it fail silently.

On iOS, @react-native-firebase gives you an FCM token rather than an APNs one, and they are not interchangeable — an FCM token sent to APNs is a BadDeviceToken on every message, forever. You do not have to say which you have: an Apple device token is 64 hexadecimal characters and a Firebase one is several times longer with a colon in it, so the SDK reads the token and routes it to the service that issued it. The source option is accepted and ignored; it asked the app a question with a silent wrong answer.

Prefer messaging().getAPNSToken() where you can. It returns Apple's own token, which Notibase delivers to directly with the .p8 you uploaded to Notibase — getToken() returns Google's, which means Firebase relays and needs its own copy of the key.

The rest of it

// Who this is. Everything they own becomes one audience member.
await Notibase.identify("user-42", { attributes: { plan: "pro" } });

// Events. `purchase` feeds attribution revenue.
await Notibase.track("viewed_cart", { items: 3 });
await Notibase.trackPurchase(499, "USD");

// Attribution: hand it the URL that opened the app.
await Notibase.handleDeepLink(url);

// Click tracking: hand it the notification's data payload.
await Notibase.trackNotificationOpen(remoteMessage.data);

// The in-app inbox.
const { items, unread } = (await Notibase.inbox()) ?? { items: [], unread: 0 };
await Notibase.inboxMarkRead(items.map((i) => i.id));

// Is any of this actually wired up? Run once from a debug build.
if (__DEV__) console.table(await Notibase.runSetupTest());

In-app messages

A message shown inside your app rather than sent to it. You publish a rule in the console; the SDK caches it and this device decides when to show it — on app open, on foreground, or when you put a value in front of it.

import { Notibase, NotibaseInAppMessages } from "@notibase/react-native";

await Notibase.enableInAppMessages({
  // Pressing an "Ask for push permission" button calls this. The SDK cannot
  // ask by itself — permission belongs to the library you already have.
  onPromptPush: () => Notifications.requestPermissionsAsync(),
  // Optional: keep a campaign link inside the app instead of the browser.
  onOpenUrl: (url) => navigation.navigate(url),
});

export default function App() {
  return (
    <NavigationContainer>
      <Routes />
      <NotibaseInAppMessages />
    </NavigationContainer>
  );
}

Mount <NotibaseInAppMessages /> once, near the root. This package owns no native module and no part of your view tree, so a message is a component you place rather than something conjured over the top of your app — which is also why your theme, your back button and your accessibility settings apply to it. If you enable in-app messages and never mount it, the SDK says so in the console rather than quietly showing nothing.

The component is normally at the root of your tree, so it is mounted while your splash or login screen is still what the person is looking at — and a message shows on top of that. Only your app knows when it has finished starting up:

Notibase.pauseInAppMessages();      // before configure()
Notibase.resumeInAppMessages();     // in the screen that replaces your splash

Notibase.inAppMessagesPaused;       // true while messages are being held

Nothing is lost while paused: rules are still fetched and the message stays eligible. Nothing is counted either — an impression is recorded when a message is drawn, so a held message has not spent its frequency cap and reports no display nobody saw. The pause is per process, so an app that pauses on every launch has to resume on every launch.

// Fires a campaign configured for "cart_value over 100", now. Local to the
// device: a trigger is a fact, not an event to report.
Notibase.setTrigger("cart_value", 240);
// Android store installs: the only thing that can carry a campaign click
// through Google Play. Add react-native-play-install-referrer and pass it on.
await Notibase.setInstallReferrer(info.installReferrer);

await Notibase.logout();        // sign-out: the device stops being theirs
await Notibase.unsubscribe();   // "turn off notifications": a durable opt-out

Signing out is not opting out. unsubscribe() records a durable opt-out against the push token — it survives sign-in, reinstall and the re-registration that happens on every launch, and is lifted only from your own backend with a server key. Reaching for it on a sign-out button silences the device for whoever signs in next, permanently. See Signing somebody out.

A message is a document of text, image, button and spacer blocks, drawn with ordinary React Native components. There is no WebView and no dangerouslySetInnerHTML anywhere in it, which is the whole reason the content is blocks rather than HTML somebody typed into a console.

The push-permission prime is the reason to reach for this first: both platforms give an app one system prompt per install and a decline is close to permanent, so it is worth spending only on somebody who already said yes inside your own UI.

What it does not do

  • No notification permission prompt and no notification display — those belong to expo-notifications or @react-native-firebase/messaging, which you already have. This SDK is the audience, targeting and reporting half.

Failures never reach your app

Every method swallows its own network errors and warns to the console. A notification SDK must not be the reason an app crashes, and an unhandled rejection in a lifecycle hook is a crash on both platforms.

Two things do throw, both before any network call and both because they fail silently forever otherwise: a server key (sk_…) — which must never be in an app bundle, because a bundle is public — and an Expo push token.

Storage

The device id has to survive a restart. @react-native-async-storage/async-storage is used if it is installed and is an optional peer dependency, not a hard one. Without it the SDK still works for the length of one launch and says so loudly: every cold start would otherwise register a new device and inflate your audience.

Any adapter with getItem/setItem/removeItem returning promises will do — expo-secure-store, MMKV, your own:

await Notibase.configure("ck_live_…", { storage: myAdapter });

Documentation

notibase.dev/react-native.html · Moving from OneSignal · REST API

Changelog

CHANGELOG.md.