A Practical Guide to Expo Push Notifications: Setup to Launch

A practical guide to implementing Expo push notifications. Learn to configure, send, and troubleshoot notifications with real-world examples for your app.

RI

By Riya

22nd Feb 2026

A Practical Guide to Expo Push Notifications: Setup to Launch

For any team building a mobile app, push notifications are non-negotiable for keeping users engaged. But let's be real—the technical setup can be a major pain. This is where Expo push notifications come in, offering a single, unified way to talk to both Apple (APNs) and Google (FCM). It lets you build powerful features that reach your users without ever getting stuck in complex native code.

Why Expo Is a Game Changer for Notifications

Traditionally, setting up push notifications meant building two entirely separate systems. You'd have one for iOS using the Apple Push Notification service (APNs) and a completely different one for Android with Firebase Cloud Messaging (FCM). This approach doubles the work, complicates maintenance, and demands platform-specific expertise just to send a simple message.

Expo flips that model on its head. It acts as a smart, reliable go-between. Instead of your server having to manage connections with both Apple and Google, it makes one simple request to Expo. Expo's servers then do the heavy lifting, navigating the complexities of APNs and FCM to make sure your notification lands on the right device, every time.

From Technical Hurdle to Product Tool

This simple change turns a major technical roadblock into a high-impact tool for product teams. For a startup trying to get its MVP out the door, this is a massive advantage. Rather than burning weeks on platform-specific setup, your team can:

  • Ship Faster: Concentrate on building core features and a great user experience, not wrestling with native notification APIs.
  • Iterate Quickly: Send beta invites with a new feature announcement, test a re-engagement campaign, and get real user feedback with a single, straightforward workflow.
  • Reduce Complexity: Your backend only has to deal with one kind of token—the Expo Push Token. This massively simplifies your database and server logic.

Push notifications are a proven channel. Globally, the average opt-in rate is over 60%, and for apps that get their strategy right, engagement rates can triple. With open rates blowing email marketing out of the water, it's a direct line to your users you can't afford to ignore.

The real magic of using Expo is that it frees your team to focus on what you want to say to your users, not get stuck on how to say it on each platform. It makes a powerful feature accessible to everyone on the team, not just specialized mobile developers.

By streamlining the process, Expo gives product teams the power to drive growth and retention without the usual technical overhead. If you're just getting started with the framework, getting a handle on the basics is the perfect first step. You might want to check out our guide on your first hour with Expo.

Getting Your Project Ready for Push Notifications

Before you can send that first notification, you need to get your project's foundation right. This means installing the right library and telling Apple and Google how to find your app. Let's walk through this setup so you can avoid headaches later.

First, you need to add the main library. Open your terminal at the root of your project and run this command:

npx expo install expo-notifications

A quick tip: always use npx expo install instead of npm or yarn. This handy command automatically grabs the library version that’s perfectly matched with your Expo SDK, saving you from a whole class of version mismatch bugs.

With that one command, your app now has the tools it needs to ask for permission, receive notifications, and react when a user taps on one.

Configuring Your app.config.js File

Think of your app.config.js (or app.json) file as your app's main control panel. For Expo push notifications to work, we need to add a few critical lines here for both iOS and Android.

For iOS, the key is the bundleIdentifier. This is a unique string, like com.yourcompany.yourapp. It’s crucial that this identifier exactly matches the App ID you set up in your Apple Developer account. This is how Apple's Push Notification service (APNs) knows which app to send notifications to.

For Android, you'll connect your app to a Firebase project. After generating a google-services.json file from your Firebase console, you just drop it into your project's root folder and point to it in your app.config.js.

The whole point of using Expo is to manage these two very different systems through a single, unified workflow.

Flowchart showing the process of simplifying iOS and Android notifications using Expo, resulting in engaged users and positive metrics like reduced uninstalls and increased open rates.

As you can see, Expo acts as the go-between, letting your team focus on building a great user experience instead of getting bogged down in platform-specific details.

Here’s what a typical configuration looks like in your app.config.js file, covering the essentials for both platforms:

// app.config.js
export default {
  expo: {
    // ... other app config
    ios: {
      bundleIdentifier: "com.yourcompany.yourapp",
      // ... other iOS config
    },
    android: {
      package: "com.yourcompany.yourapp",
      googleServicesFile: "./google-services.json",
      // ... other Android config
    },
    plugins: [
      "expo-notifications"
    ]
  }
};

The Bottom Line: Don't skip the bundleIdentifier for iOS or the google-services.json file for Android. These are the credentials your app needs to talk to Apple's and Google's notification servers. They are non-negotiable.

With this setup in place, your project is now primed to handle Expo push notifications. The next steps are to ask your users for permission and grab their unique device token. If you're just getting started, our guide on how to create an Expo app from scratch can help get you up and running.

Handling Permissions and Capturing Push Tokens

Now that your project configuration is sorted, it's time to focus on your users—specifically, asking for their permission to send them notifications.

This isn't just a technical step; it's a critical moment in the user experience. If you ask at the wrong time, a user might hit "Deny" and you could lose that communication channel for good. The trick is to ask when the value is crystal clear. For example, in a messaging app, ask after they've sent their first message, not on the first app open.

A person holds a smartphone displaying a green shield security logo, with 'Grant Permission' text overlaid.

Gracefully Requesting User Permission

A best practice is to check the permission status before you show the native iOS or Android dialog. This lets you build a smarter experience, like showing a custom screen explaining why you need permissions before popping the official request.

The expo-notifications library gives you everything you need with getPermissionsAsync() and requestPermissionsAsync().

Here’s a practical approach:

  • Check first, ask second. When a key component loads (like a user's profile), use getPermissionsAsync() to check the status.
  • Ask thoughtfully. If permissions haven't been granted, that's your cue to call requestPermissionsAsync(), which brings up the native dialog.
  • Handle denial gracefully. If the status is 'denied,' respect it. The best you can do is offer a clear path for the user to enable notifications later in the app's settings if they change their mind.

Capturing the Unique Expo Push Token

Once a user gives you the green light, it's time to get their unique Expo Push Token. Think of this token as the direct mailing address for their device. Without it, you can't send them a thing.

You grab this token by calling getExpoPushTokenAsync(). This function talks to Expo's servers, which coordinate with APNs and FCM to create a single, unified token that works on both iOS and Android.

The Expo Push Token is the key that unlocks targeted communication. Once you have it, your backend system can send a message directly to that specific user, whether they're on an iPhone or an Android device.

This is a huge win for any team. Expo lets you sidestep the complexities of managing different device tokens, offering a unified API that supports everything from simple text to sounds and badges out of the box.

Securing the Token on Your Backend

Getting the token on the device is only half the battle. To use it, you need to send it to your backend and store it securely, linking it to a user's account in your database.

This step is critical for sending notifications that matter. When a user gets a new follower, your server needs to look up that user's push token to ping their device and only their device. Properly handling sensitive data like push tokens is a core part of app security, making it a good time to brush up on Mastering Application Security Best Practices.

Sending and Responding to Notifications

Alright, you've got the user's permission and their push token. Now the real fun begins: sending messages and making your app react when a user taps on them. This is where your push notification strategy goes from setup to real-world engagement.

For quick tests, you don't even need a backend. Expo has a fantastic Push Notification Tool that's perfect for this. It's a lifesaver when a product manager wants to test notification copy or a designer needs to see how a deep link feels, all without waiting on a server deployment. You just drop in an Expo Push Token, craft your message, and send.

A person holds a smartphone displaying an app next to a tablet, both showing digital interfaces for sending and responding.

Sending Notifications from Your Server

When you're ready to automate, you'll be firing off notifications from your server. This is how you trigger pushes based on events, like a new friend request or an order confirmation. Expo makes this incredibly simple with their expo-server-sdk.

Here’s a practical example using Node.js. After installing the SDK, you can create a function to send a notification to a specific user's token.

// On your Node.js server
import { Expo } from 'expo-server-sdk';

// Create a new Expo client
const expo = new Expo();

async function sendPushNotification(pushToken, messageTitle, messageBody, data) {
  // First, check if it's a valid token
  if (!Expo.isExpoPushToken(pushToken)) {
    console.error(`Push token ${pushToken} is not a valid Expo push token`);
    return;
  }

  // Build the message payload
  const message = {
    to: pushToken,
    sound: 'default',
    title: messageTitle,
    body: messageBody,
    data: data, // e.g., { screen: 'UserProfile', userId: '123' }
  };

  try {
    // Send it!
    const ticket = await expo.sendPushNotificationsAsync([message]);
    console.log('Notification sent! Ticket:', ticket);
  } catch (error) {
    console.error('Error sending push notification:', error);
  }
}

Pay close attention to that data object. It’s where the real magic happens. This is how you pass extra information along with the notification—like a user ID or a screen name—that your app can use to decide what to do next.

A common pitfall developers run into is forgetting to handle "chunks." Expo's API prefers you to send notifications in batches to avoid overwhelming their servers. The expo-server-sdk has helpers for this, and it's a critical concept to grasp as your user base grows.

Responding to Notifications in Your App

Sending the notification is only half the battle. The user experience comes to life when your app responds intelligently to a tap. With expo-notifications, we can set up "listeners" that wait for these events.

You'll primarily work with two listeners:

  • addNotificationReceivedListener: This fires the moment a notification arrives while the app is running in the foreground. You might use this to show a custom in-app banner or refresh some data without interrupting the user.
  • addNotificationResponseReceivedListener: This is the big one. It fires when a user taps on a notification, whether the app was in the foreground, background, or completely closed.

Let's imagine a real-world scenario. In a social media app, a user gets a push about a new comment on their post. When they tap it, you want the app to open directly to that specific post. To do this, you’d include the postId in the notification's data payload. The listener in your app would then read that postId and use your navigation logic to take the user right there.

The impact of this kind of targeted messaging is massive. Research shows personalized pushes can boost engagement by up to 88%. By pairing a smart server-side strategy with responsive client-side listeners, you can turn simple alerts into meaningful interactions that guide users exactly where they need to go. If you're looking for more advanced patterns, you can learn more about push notifications in React Native in our comprehensive guide.

Solving Common Expo Notification Problems

Sooner or later, you're going to hit a wall with notifications. It happens to everyone. Getting stuck on why a push isn't showing up can be incredibly frustrating, so let's walk through some of the most common issues.

This is your cheat sheet for getting unstuck fast. The goal is to help you pinpoint the problem, fix it, and move on.

Problem: Notifications Not Arriving on TestFlight Builds

This one is a classic. Everything works perfectly in Expo Go, but the second you create an iOS build for TestFlight, your notifications vanish. Nine times out of ten, this is a credentials problem.

For a TestFlight or App Store build, Apple requires a specific production provisioning profile. That profile must have the "Push Notifications" capability enabled.

Run through this quick checklist:

  • Provisioning Profile Mismatch: In your Apple Developer account, check that your provisioning profile has push notifications enabled and matches the bundleIdentifier in your app.config.js. Did you upload the correct one to your build service?
  • APNs Key Configuration: Head back to your Expo project dashboard and confirm your Apple Push Notification service (APNs) key is uploaded and correctly configured. A missing or invalid key is an instant dealbreaker.

I’ve watched teams lose hours to this exact issue. If it works in development but breaks in production, your first suspect should always be your build credentials, not your code.

Problem: Android Notifications Fail to Deliver

On the Android side, a similar headache often boils down to a single file: google-services.json. This file is the bridge connecting your app to your Firebase project, which is what delivers the notification.

If your Android pushes aren't making it through, here's where to look:

  • Incorrect google-services.json: Double-check that the google-services.json file in your project root is the one that belongs to the package name in your app.config.js. It's surprisingly easy to grab the file from an old or different Firebase project by mistake.
  • FCM API Not Enabled: Hop into your Google Cloud Platform console and make absolutely sure the Firebase Cloud Messaging API is enabled for your project.

These configuration files are the linchpin holding your app and the native push services together. A tiny mismatch can cause everything to fail silently. Getting this right is critical, especially when you consider that many marketers see push notifications as a key driver for user retention. You can learn more about the impact of push notifications on user engagement.

Got Questions About Expo Push Notifications?

Even with a guide, you're bound to run into specific questions. Let's tackle some of the most common ones we see from teams working with Expo push notifications.

Can I send pushes without setting up a server?

For testing and debugging? Absolutely. Expo has a handy web-based Push Notification Tool that lets you send a message directly to a device as long as you have its Expo Push Token. It's a lifesaver for quick checks.

However, for a real app, you'll need a backend. Your server is what triggers notifications based on events, like a new message or a sale ending. That's when you'll use tools like the expo-server-sdk for your Node.js server.

Do Expo Push Notifications work in the Bare Workflow?

Yes, they work great. While the managed workflow automates a lot of the setup, the expo-notifications library is fully compatible with the bare workflow.

The main difference is you’re responsible for the native project configuration. This means you'll be manually setting up Firebase for Android and your APNs credentials for iOS—the same steps Expo CLI would otherwise handle for you.

How do I handle a notification when the app is closed?

This is a critical one. To manage notifications when your app is completely closed (or "killed"), you need to set up a background notification handler using the setNotificationHandler method from the expo-notifications library.

Then, when a user taps that notification, your app will launch from a cold start. From there, your addNotificationResponseReceivedListener will grab the notification's data and route the user to the right screen.

Getting your background handlers right is a huge deal for engagement. Users who get push notifications show 3x higher retention rates, and personalizing them can boost that even further. You can dig into more data on how push notifications impact user retention.

What's the difference between an Expo token and a native token?

Think of it this way: a native token comes directly from Apple (APNs) or Google (FCM). An Expo Push Token is a single, unified token that Expo generates to hide that complexity from you.

When you send a notification to Expo's servers with an Expo Push Token, Expo figures out if it’s an iOS or Android device and delivers it using the correct native token. It massively simplifies your backend code.


Ready to build your mobile app faster? RapidNative is an AI-native platform that turns your ideas into production-ready React Native code in minutes. Go from prompt, sketch, or PRD to a working prototype and iterate with your team in real time. Start building for free at RapidNative.

Ready to Build Your mobile App with AI?

Turn your idea into a production-ready React Native app in minutes. Just describe what you want to build, andRapidNative generates the code for you.

Start Building with Prompts

No credit card required • Export clean code • Built on React Native & Expo