ExpoNotificationsPush NotificationsReact Native

How to Add Push Notifications to an Expo App (expo-notifications)

A step-by-step guide to local and push notifications in Expo — set up expo-notifications, request permissions, schedule local reminders, get an Expo push token, and handle taps. SDK 54+ examples.

DeveloperMill3 min read

Push notifications are one of the highest-impact features you can add to a mobile app — and one of the most-searched Expo topics. expo-notifications gives you a single API for both local notifications (scheduled on the device) and remote push notifications (sent from your server). This guide walks through both.

Install

npx expo install expo-notifications expo-device expo-constants

expo-device lets you check for a physical device (required for push), and expo-constants gives you the project ID you need to fetch a token.

Configure the notification handler

Set a handler once, near your app's entry point, so notifications display even when the app is open:

import * as Notifications from "expo-notifications"

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowBanner: true,
    shouldShowList: true,
    shouldPlaySound: true,
    shouldSetBadge: false,
  }),
})

Request permission

Always ask before scheduling or registering:

async function requestPermission() {
  const { status } = await Notifications.requestPermissionsAsync()
  return status === "granted"
}

Schedule a local notification

Local notifications need no server — perfect for reminders, timers, and streaks:

await Notifications.scheduleNotificationAsync({
  content: {
    title: "Time to stretch 🧘",
    body: "You've been coding for an hour.",
  },
  trigger: { seconds: 60 * 60, repeats: true },
})

Triggers can be a delay ({ seconds }), a calendar date, or a daily time.

Get an Expo push token

To receive remote notifications, register the device and send its token to your backend:

import * as Notifications from "expo-notifications"
import * as Device from "expo-device"
import Constants from "expo-constants"

async function registerForPush() {
  if (!Device.isDevice) return // must be a physical device

  const { status } = await Notifications.requestPermissionsAsync()
  if (status !== "granted") return

  const projectId = Constants.expoConfig?.extra?.eas?.projectId
  const token = await Notifications.getExpoPushTokenAsync({ projectId })
  return token.data // "ExponentPushToken[xxxxxxxx]"
}

Send that token to your server and store it against the user.

Set up an Android channel

Android requires a channel for notifications to appear. Create one at startup:

import { Platform } from "react-native"

if (Platform.OS === "android") {
  await Notifications.setNotificationChannelAsync("default", {
    name: "Default",
    importance: Notifications.AndroidImportance.DEFAULT,
  })
}

Handle taps and incoming notifications

Listen for notifications received while the app runs, and for the user tapping one:

import { useEffect } from "react"

useEffect(() => {
  const received = Notifications.addNotificationReceivedListener((n) => {
    console.log("received:", n.request.content.title)
  })

  const responded = Notifications.addNotificationResponseReceivedListener((r) => {
    // e.g. navigate based on r.notification.request.content.data
    console.log("tapped:", r.notification.request.content.data)
  })

  return () => {
    received.remove()
    responded.remove()
  }
}, [])

Send a test push

Once you have a token, hit the Expo Push API:

curl -X POST https://exp.host/--/api/v2/push/send \
  -H "Content-Type: application/json" \
  -d '{ "to": "ExponentPushToken[xxxx]", "title": "Hello", "body": "First push 🎉" }'

Gotchas

  • Physical device required for remote push — emulators can't get a token.
  • Add the expo-notifications config plugin (and an icon) in app.json for a production build.
  • Store the token server-side; it can change, so refresh it on app launch.

Next steps

Notifications usually go hand-in-hand with a backend and auth. Read how to add authentication to an Expo app, and see the full list in the top 10 Expo SDK modules.

Frequently asked questions

Can I test push notifications on a simulator?

No. Remote push notifications require a physical device — iOS simulators and Android emulators can't register for a push token. Local notifications (scheduled on-device) do work in simulators, so you can build and test scheduling logic there.

Do I need Firebase to send push notifications with Expo?

Not to get started. Expo's push service handles delivery to both iOS (APNs) and Android (FCM) through a single Expo push token. For production Android you'll configure FCM credentials, but you send everything through the same Expo Push API.

Why is my notification not showing when the app is open?

By default iOS suppresses notifications while the app is foregrounded. Call `Notifications.setNotificationHandler({...})` and return `shouldShowBanner: true` so foreground notifications appear.

Build it faster with a template

Production-ready Expo React Native templates with the patterns from this post already wired up.

Browse templates