# Installation

Learn how to install and setup Native Notify push notifications in React Native Expo apps.

> **Not an Expo app?:**
>
> Everything on this page assumes the **Expo SDK path** (`native-notify` +
> `registerNNPushToken()`). If you are building with **Flutter, bare React
> Native without Expo modules, native Swift or Kotlin**, start with
> [Universal Push (Any Framework)](/docs/universal-push) instead — same
> service, native APNs/FCM tokens, no SDK required.

This video walks through the setup guide below:

[YouTube video player](https://www.youtube.com/embed/JO850zWNwoY?rel=0)

## Prerequisites

1. **Create a free NativeNotify.com account**

   You must create a free [NativeNotify.com](https://dashboard.nativenotify.com/sign-up-one) account to get your App ID and App Token. You need an App ID and App Token for Native Notify push notifications to work.

2. **Create a free Expo.dev account**

   You must create a free [https://Expo.dev](https://expo.dev) account for Native
   Notify push notifications to work.

3. **System Requirements**

   - **Node.js:** Make sure you have Node.js installed. The project uses `npm`, which comes with Node.js. Install Node.js from [nodejs.org](https://nodejs.org).
   - **NPM or Yarn:** Since the project uses `npm` commands, ensure that npm is installed with Node.js. Alternatively, you can use Yarn if preferred.

   To verify installation, run:

   ```bash
   node -v
   npm -v
   ```

4. **Expo Setup**

   You need Expo installed in your React Native app in order for Native Notify push notifications to work. Native Notify push notifications work in Expo "managed workflow" and/or "bare workflow". You do NOT have to eject out of Expo to use Native Notify push notifications.

   If you have not yet added Expo to your existing React Native app, visit this link to learn how to get Expo set up in your existing React Native app:

   [https://docs.expo.dev/bare/installing-expo-modules](https://docs.expo.dev/bare/installing-expo-modules)

## Installation and setup

1. **Install Native Notify**

   Run the following commands in your Expo project terminal:

   ```bash
   npm install native-notify
   npx expo install expo-device expo-notifications expo-constants
   ```

   - `expo-constants` is a **required peer dependency** — native-notify imports it to resolve your EAS `projectId`.
   - `expo-notifications` also needs its config plugin in your **app.json** — it is **required for push notifications in development builds and EAS builds**:

   ```json
   {
     "expo": {
       "plugins": ["expo-notifications"]
     }
   }
   ```

   > **Expo Go on Android (SDK 53+):**
   >
   > Push notifications are not supported in Expo Go on Android — Expo Go cannot mint push tokens. Use a development build instead (`npx expo run:android` or an EAS development build). The [Notification Inbox](/docs/indie-notification-inbox/components) still works in Expo Go with `mode="indie"`.

2. **Import Native Notify**

   In your App.js or index.js file (for Expo 50+), include this import at the top of the screen:

   ```bash
   import registerNNPushToken from 'native-notify';
   ```

3. **Check for Hook function**

   Make sure your App.js or index.js file (for Expo 50+) is a Hook function. Here is an example:

   ```bash
   export default function AppPage() {
       ...
   }
   ```

   - This link explains Hooks in detail: [https://react.dev/reference/react/hooks](https://react.dev/reference/react/hooks)

   - If you are using a class component, this link shows how to wrap a class component inside of a hook function allowing you to still use Native Notify in a class component: [https://github.com/NativeNotify/wrap-class-in-hook](https://github.com/NativeNotify/wrap-class-in-hook)

4. **Paste register function**

   Inside of your App function, at the top of your App function, paste this code:

   ```bash
   registerNNPushToken(app-id-number, 'app-token-string');
   ```

   Here is a complete example:

   ```bash
   import React, { useState, useEffect } from 'react';
   import registerNNPushToken from 'native-notify';

   export default function AppPage() {
       registerNNPushToken(app-id-number, 'app-token-string');

       return (
         ...
       )
   }
   ```

5. **Optional: configure your credentials once**

   Instead of passing `appId` and `appToken` to every call, you can set them once — with a provider:

   ```jsx
   import { NativeNotifyProvider } from 'native-notify';

   export default function App() {
     return (
       <NativeNotifyProvider appId={yourAppId} appToken="yourAppToken">
         <Root />
       </NativeNotifyProvider>
     );
   }
   ```

   or at module scope (works for the plain, non-React functions):

   ```js
   import { NativeNotify } from 'native-notify';

   NativeNotify.init({ appId: yourAppId, appToken: 'yourAppToken' });
   ```

   Every function still accepts explicit ids, so nothing changes if you keep passing them. When the ids are omitted, hooks and components (`registerNNPushToken`, the inbox components) read `<NativeNotifyProvider>` first, then `NativeNotify.init()`; plain functions (`registerIndieID`, the follow, inbox and send functions, analytics reports) read `NativeNotify.init()` only — use `init()` if you call those. Inside a component you can read the active config with `useNativeNotify()`.

6. **Optional: registration callbacks and token rotation**

   ```js
   registerNNPushToken(yourAppId, 'yourAppToken', {
     onRegistered: (result) => console.log('native-notify ready:', result.expoPushToken),
     onError: (error) => console.warn('native-notify registration failed:', error),
   });
   ```

   - `onRegistered(result)` — called after the token was registered with Native Notify.
   - `onError(error)` — called when registration (or a token-rotation re-registration) fails.
   - `watchTokenRotation` (default `true`) — automatically re-registers when the device push token rotates (Android reinstall / applicationId change, iOS backup restore).

   Registration retries once on failure and has a 10-second timeout. To run the raw token flow yourself, use the exported `registerForPushNotificationsAsync()` — it never throws, it reports:

   ```js
   import { registerForPushNotificationsAsync } from 'native-notify';

   const result = await registerForPushNotificationsAsync();
   if (result.status === 'success') {
     // result.expoPushToken, result.devicePushToken, result.expoAndroidToken, ...
   } else {
     console.warn(result.status, result.reason); // status is 'skipped' or 'error'; reason says why
   }
   ```

## Test if push notifications are working

1. **Install eas-cli**

   Run the following commands in your Expo project terminal:

   ```bash
   npm install -g eas-cli
   ```

2. **eas login**

   If you have not logged into your eas account, run the following command in your terminal and follow the instructions:

   ```bash
   eas login
   ```

3. **eas init**

   Run the following command in your terminal and follow the instructions to ensure your project has a projectId (your app requires an eas projectId for push notifications to work):

   ```bash
   eas init
   ```

   This writes `extra.eas.projectId` into your **app.json**. Native Notify resolves it with Expo's recommended fallback chain:

   ```js
   Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId
   ```

   If neither value is present, registration fails with a clear "no EAS projectId found" message — see [Expo's Configure projectId docs](https://docs.expo.dev/push-notifications/push-notifications-setup/#configure-projectid).

4. **npx expo start**

   Run the following command in your terminal to start the dev server:

   ```bash
   npx expo start
   ```

   Then open the app — in Expo Go on iOS, or in a development build on Android (`npx expo run:android` or an EAS dev build).

5. **Open your app**

   Open your app on your iOS phone or Android phone. If you have not downloaded the Expo Go app yet, here is the link:

   [https://expo.dev/go](https://expo.dev/go)

   > **Where push notifications work:**
   >
   > - **iOS:** physical iPhones (Expo Go included). iOS Simulators on Xcode 14+ (macOS 13+, iOS 16+) can also receive push.
   > - **Android:** physical phones and emulators with Google Play services — but **not Expo Go** (SDK 53+). Use a development build.

6. **Send yourself a push notification**

   Post to this URL:

   ```bash
   https://app.nativenotify.com/api/notification
   ```

   Use this POST body (replacing the 'dateSent' with your current date as a string):

   ```bash
   {
      appId: app-id-as-a-number,
      appToken: "app-token-as-a-string",
      title: "Push title here as a string",
      body: "Push message here as a string",
      dateSent: "put your date here as a string"
   }
   ```

   **Notes:**

   - Send the body as JSON with the `Content-Type: application/json` header. axios sets it for you; `fetch` and server languages such as Python must set it — without it the server cannot read your `appId` / `appToken` and answers `401`.
   - Expo limits a push message to **4 KiB** (4096 bytes) — the whole message counts (title, body, `pushData` and any rich fields). A larger one is refused with `400` and `notification payload exceeds Expo's 4KiB limit`.

   **Alternative: Expo's push notifications tool.** After your app registers, the device has an Expo push token (it starts with `ExponentPushToken[`). Paste it into [https://expo.dev/notifications](https://expo.dev/notifications), add a title and body, and send — a quick way to verify device-side setup without the Native Notify API.

## Next, setup iOS and/or Android Production Notifications

- [**iOS**](/docs/setup/ios) — iOS Production Push Notification Setup Next Steps

- [**Android**](/docs/setup/android) — Android Production Push Notification Setup Next Steps
