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

@callstack/react-native-local-notifications

v0.1.1

Published

Consume the local-notification action that cold-started a React Native app

Readme

@callstack/react-native-local-notifications

Recover the local-notification action that launched your React Native app from a terminated state.

@callstack/react-native-local-notifications bridges the cold-start notification response to JavaScript on iOS and Android. It gives your navigation or analytics code one consistent, typed action without taking ownership of notification scheduling or live notification events.

Third-party services such as Braze or Firebase often already handle actions from remote notifications. This library is intended for applications where local and remote notifications use different mechanisms: keep using your existing provider for remote notifications, and use this package to recover the initial action from a local notification when it launches the app.

Why use it?

  • Handles notification actions that launch a terminated app
  • Provides the same typed result on iOS and Android
  • Consumes each launch action exactly once
  • Works alongside your existing notification library and event listeners
  • Uses a New Architecture TurboModule with no retained native notification objects

Installation

yarn add @callstack/react-native-local-notifications

Or use your preferred package manager:

npm install @callstack/react-native-local-notifications
# or
pnpm add @callstack/react-native-local-notifications

Install iOS pods after adding the package:

cd ios && pod install

Autolinking handles the native module. React Native's New Architecture must be enabled.

Quick start

Read the initial action once during application startup:

import { useEffect } from 'react';
import { getInitialNotificationAction } from '@callstack/react-native-local-notifications';

function App() {
  useEffect(() => {
    getInitialNotificationAction()
      .then((action) => {
        if (!action) return;

        // Navigate, update state, or record analytics.
        console.log('App opened from notification', action);
      })
      .catch((error) => {
        console.warn('Could not read the initial notification action', error);
      });
  }, []);

  return null;
}

The result looks like this:

{
  notificationId: '2137',
  categoryId: 'CATEGORY_ID',
  channelId: 'example_channel', // Android only
  action: 'tapped',
  actionIdentifier: null,
}

Before calling the JavaScript API, add the small native capture hook for each platform.

Native setup

Android

Capture the launch intent in your MainActivity before calling super.onCreate:

import android.os.Bundle
import com.localnotifications.InitialNotificationAction

override fun onCreate(savedInstanceState: Bundle?) {
  InitialNotificationAction.captureInitialIntent(intent)
  super.onCreate(null)
}

Do not capture onNewIntent events. Those happen while the app is already alive and should continue through your existing notification event listener.

iOS

Expose the library header from your application's bridging header:

#import <InitialNotificationActionStore.h>

Then capture the notification response in your SceneDelegate before starting React Native:

func scene(
  _ scene: UIScene,
  willConnectTo session: UISceneSession,
  options connectionOptions: UIScene.ConnectionOptions
) {
  if let response = connectionOptions.notificationResponse {
    InitialNotificationActionStore.capture(response)
  }

  // Start React Native after capture.
  // factory.startReactNative(...)
}

The library does not install a UNUserNotificationCenterDelegate, so it will not interfere with the delegate or notification library you already use.

Using cold-start and live actions together

This package only handles the action that launches a terminated app. Keep your existing listener for foreground, background, and warm-start actions.

Subscribe to live events first, then retrieve the cold-start action. This avoids losing an event during application startup:

useEffect(() => {
  let cancelled = false;

  const handleAction = (action: NotificationActionInformation) => {
    // Use one navigation path for cold-start and live actions.
  };

  // additional subscription to notifications
  const subscription = subscribeToRemoteNotificationActions(handleAction);

  getInitialNotificationAction()
    .then((action) => {
      if (!cancelled && action) handleAction(action);
    })
    .catch((error) => {
      console.warn('Could not read the initial notification action', error);
    });

  return () => {
    cancelled = true;
    subscription.remove();
  };
}, []);

subscribeToRemoteNotificationActions is a placeholder for the listener supplied by your notification solution; it is not exported by this package.

API

getInitialNotificationAction()

function getInitialNotificationAction(): Promise<InitialNotificationAction | null>;

Returns the notification action that launched the current application process, or null when the app was opened normally or the action has already been consumed.

type InitialNotificationActionType = 'tapped' | 'clear' | 'customAction';

type InitialNotificationAction = {
  notificationId: string;
  categoryId: string | null;
  channelId: string | null;
  action: InitialNotificationActionType;
  actionIdentifier: string | null;
};

| Field | Description | | ------------------ | ------------------------------------------------------------- | | notificationId | Identifier of the notification that triggered the action | | categoryId | Notification category, when supplied | | channelId | Android notification channel; always null on iOS | | action | Normalized tap, clear, or custom action | | actionIdentifier | Platform action identifier for a custom action, when supplied |

The value is held in memory and atomically consumed. The first call receives it; later or concurrent calls return null. It is not persisted between application processes.

What this library does not do

To stay small and composable, the package does not:

  • display or schedule notifications
  • request notification permissions
  • handle foreground, background, or warm-start events
  • install notification delegates
  • persist notification actions

Use it as the cold-start companion to your existing notification solution.

Testing

A Jest mock is available as a package export:

moduleNameMapper: {
  '^@callstack/react-native-local-notifications$':
    '@callstack/react-native-local-notifications/jest/mock',
}

The mock resolves to null by default. You can replace or spy on getInitialNotificationAction in tests that need a launch action.

The repository also includes an example application demonstrating native capture and consume-once behavior on both platforms.

Contributing

Contributions of all sizes are welcome. See the contributing guide for local setup, development commands, and pull request guidance. Please follow the project code of conduct.

License

MIT