How to Add Push Notifications to a Mobile App
Contents
Push notifications are useful when they bring someone back to a task they already care about: a reply needs attention, an order changed, a booking was confirmed, or a time-sensitive reminder is due. They become noise when they exist only to create another open.
A reliable implementation is not just a device token and a “Send” button. It needs a clear event, permission at the right moment, a trusted backend, a safe destination after the tap, user controls, and a way to learn whether the notification helped.
Ask for notification permission after the user sees its value, store tokens as revocable device records, send from a trusted backend rather than the app, deep-link to an authorized destination, separate required service updates from optional engagement, and test permission, token, and tap flows on real release builds.
Start with one user event
Write the notification as a product rule before choosing a provider.
| Product event | Useful notification | Destination after tap | Can the user turn it off? |
|---|---|---|---|
| A customer’s order changes status | “Your order is out for delivery” | That order’s tracking screen | Usually no for essential status updates |
| A marketplace seller receives an offer | “You received an offer on your bike” | The offer thread | Yes |
| A user’s coach replies | “Maya replied to your plan” | The specific conversation | Yes |
| A medication reminder is due | “Time for your 8:00 PM reminder” | Today’s reminder | Yes, with schedule controls |
| A new comment arrives | “3 new comments on your post” | The post or activity feed | Yes |
Avoid starting with “send a notification when someone has been inactive for three days.” First identify the missed value: an unfinished plan, a saved item that changed, or a collaboration task that needs a response. If the action after the tap is unclear, the notification is probably not ready.
Keep transactional and engagement notifications separate. A booking cancellation, security alert, or completed payment is part of the service. A weekly prompt to return is optional marketing. They need different preferences, copy, frequency limits, and reporting.
Understand the delivery path
A remote push crosses several systems. The mobile app registers a device token. Your backend decides whether an event deserves a notification. A provider then delivers it through Apple Push Notification service (APNs) or Firebase Cloud Messaging (FCM).
The operating system, not your app, controls final presentation. A valid send does not guarantee that a banner appears immediately: the user may have denied permission, enabled Focus mode, muted a channel, or lost connectivity.
For Expo projects, Expo Notifications can obtain device or Expo push tokens, handle incoming notifications, and react to notification taps. Expo’s push service simplifies the APNs/FCM handoff, while a direct provider setup gives your backend more control. Either way, the send credentials belong in a trusted server environment, not in the mobile client.
Ask for permission after value is visible
Do not show the operating-system prompt on the first launch before the user understands the app. Let the person complete an action that makes notifications useful, then show a short pre-permission explanation.
For example:
- A buyer enables order tracking.
- The app explains: “Get delivery updates for this order. You can change this anytime.”
- The user taps Turn on updates.
- The app requests the system permission.
- If declined, the order screen still works and offers email or in-app status checks.
On Android 13 and later, notification permission is opt-in. With Expo, create an Android notification channel before requesting an Expo or device push token; its documentation explains the required order. On iOS, distinguish between a user who has not decided, denied access, granted access, or has provisional authorization. Do not repeatedly trigger the system prompt after a denial—show a respectful Settings path only when the user asks to enable a feature.
A good permission screen answers three questions:
- What specific updates will arrive?
- How often will they arrive?
- What can the user control later?
“Enable notifications” is not an explanation.
Treat each token as a device record
A token identifies an app installation, not a permanent user identity. A person may use multiple phones, reinstall the app, sign out, or disable permission. Model it accordingly.
| Field | Why it matters |
|---|---|
id | Stable database record |
user_id | Authenticated owner, if signed in |
token | Provider token; protect it like account data |
provider | Expo, APNs, or FCM |
platform | iOS or Android |
installation_id | Distinguishes multiple devices |
permission_status | Prevents pointless sends |
last_seen_at | Helps retire stale records |
disabled_at | Keeps an audit trail after a failure or sign-out |
Register or refresh the token after permission is granted and whenever the app starts from an authenticated session. Tie the record to the verified user on the server; never let the client claim another user’s ID.
When the user signs out, revoke or disassociate the device record. When a provider reports an invalid or unregistered token, mark it inactive. Do not keep attempting the same failed send forever.
Send only from the backend
The app may request an action, but it should not decide and send the final notification. Your backend has the event data, recipient authorization, preference state, rate limits, and provider credentials.
A safe send flow looks like this:
Firebase Cloud Messaging likewise separates the client app from a trusted environment that builds and sends messages. Never ship an FCM server credential, APNs private key, or provider secret inside an Expo, React Native, Flutter, or Swift app.
Create a notification log with the event type, recipient, destination, sent time, provider response, and whether the user opened it. This makes duplicate sends and support investigations much easier to diagnose.
Make every notification open a safe screen
A notification payload should contain only the information needed to route the user, such as:
When the app opens:
- Read the route data.
- Restore the user session if necessary.
- Fetch the current record from the backend.
- Verify the signed-in user may access it.
- Show an unavailable state if the record was deleted, cancelled, or no longer belongs to them.
Do not put sensitive data in a payload just because the app can display it. Notification previews can appear on a locked screen, and a stale payload is not a source of truth. Expo documents how to respond to taps and route with deep links in its notification handling guide.
Design notification categories and controls
A single master toggle is rarely enough. Create understandable categories that map to real user choices.
| Category | Examples | Default |
|---|---|---|
| Account and security | New login, password reset | On |
| Transactional updates | Delivery, appointment, payment status | On when relevant |
| Direct activity | Replies, messages, assigned tasks | On |
| Reminders | Habits, due dates, saved plans | User-controlled |
| Product updates | Tips, new features, promotions | Off or opt-in |
Keep the controls in the app even though iOS and Android also offer operating-system controls. Your backend must respect the app-level preferences before it calls a provider.
On Android, notification channels also let users control categories at the operating-system level. Do not create a channel for every individual message; use a small, stable set such as messages, orders, and reminders. Once users lower a channel’s importance, your app should still work without banners or sound.
Protect attention with frequency and timing rules
A notification system needs limits before it needs clever copy.
Set rules for:
- Maximum promotional notifications per week.
- Quiet hours in the user’s selected timezone.
- A cooldown after a user ignores a similar prompt.
- Deduplication when the same event is processed twice.
- Grouping for multiple events, such as “3 new comments.”
- A clear priority order when several events compete.
Use local time only when you know the user’s timezone and have a meaningful reason to send at that time. “8:00 AM everywhere” is not the same as “8:00 AM for this user.”
For reminders that must occur on the device even without a network connection, local scheduling can be appropriate. For server-side events such as a new order or message, use remote notifications. Keep these two cases separate in your product model.
Handle foreground, background, and failure states
The experience differs depending on app state.
| State | Expected behavior |
|---|---|
| App open in the relevant screen | Update the screen; do not interrupt with a redundant banner |
| App open elsewhere | Show an in-app message only when it helps |
| App backgrounded | Let the system present the configured notification |
| App closed, then opened from a tap | Restore session, route safely, fetch fresh data |
| Permission denied | Keep the feature usable and offer in-app/email alternatives where sensible |
| Token invalid | Stop sending and register a new token on a future app session |
Remote push testing should use a development or production build, not just a preview. In particular, Expo notes that remote push support is unavailable in Expo Go on Android from SDK 53; use a development build or release build for the real flow.
Measure whether notifications help
Open rate is not enough. A dramatic notification may earn taps and still damage trust.
Track the full path:
| Metric | What it tells you |
|---|---|
| Eligible users | Whether the audience is defined correctly |
| Send and provider errors | Token or provider health |
| Delivered/opened where available | Basic reach and interest |
| Destination completed | Whether the notification led to useful action |
| Preference changes and opt-outs | Whether it felt excessive |
| 7- and 30-day retention by cohort | Whether the system creates lasting value |
Compare a notification against a clear product outcome, such as completed check-ins, attended appointments, resolved support tasks, or repeat purchases. Do not optimize for notifications sent.
Test the whole system before launch
Test on physical iOS and Android devices with release-like credentials.
- Permission granted, denied, and later changed in Settings.
- A user with two devices and a user who signs out.
- Foreground, background, and closed-app taps.
- A destination the user can no longer access.
- Expired or invalid tokens.
- Duplicate event delivery and retry behavior.
- Android channel changes and iOS notification settings.
- Quiet hours, timezone changes, and grouped events.
- A slow or unavailable backend after the user taps.
- Sensitive content with lock-screen previews disabled.
Use the broader mobile app testing guide before store submission.
Build a useful notification system with Huxly
Huxly can help you build the notification settings screens, authenticated device records, backend event logic, deep-link destinations, and real-device testing flow in one mobile app project. The important part is defining the user event and safety rules first; then the app and backend can be built around a system people will choose to keep enabled.
FAQ
Do I need a backend to send push notifications?
For notifications triggered by orders, messages, subscriptions, or other shared data, yes. A trusted backend should decide the recipient, enforce preferences, and keep provider credentials private. Local notifications can run on-device for simple reminders.
Should I ask for notification permission on the first screen?
Usually no. Ask after the user understands the benefit, such as enabling delivery tracking or message alerts. An early unexplained prompt is easy to deny.
Can I send the full private message in the notification body?
You can, but consider lock-screen privacy first. A safer default is a generic preview such as “You have a new message,” then fetch the content after authorization in the app.
Why does a push work in development but not after release?
Credentials, bundle identifiers, Android channels, provider configuration, and build type can all differ. Test the same release-like build and environment you plan to submit.
How do I stop duplicate notifications?
Give each product event an idempotency key, log the planned notification before sending, and prevent a second worker or retry from creating another notification for the same recipient and event.
Are push notifications required for App Store approval?
No. They are optional. If you use them, make their purpose clear, respect permissions, and ensure the app still handles the related feature when notifications are unavailable.
Conclusion
A good push notification is a continuation of a useful product moment, not a shortcut to more opens. Define the event first, request permission in context, keep provider credentials on the backend, and route every tap to fresh authorized data.
When the system also respects preferences, quiet time, token changes, and real-device failure cases, notifications become a dependable part of the app instead of a source of churn.
