Build the mental model
A push notification is triggered from outside the device: your backend, or a third-party service acting for it, decides that something happened -- a new chat message, a comment, a completed payment -- and delivers that information to the device even while the app is closed or the phone is asleep.
A local notification, by contrast, is scheduled entirely by the app itself, on the device, with no server involved at all: a study reminder at 8 PM, a workout timer finishing, a habit-tracking nudge the app set hours earlier.
Register
The app registers with the platform's notification system once the user grants permission.
Receive Device Token
The platform returns a device token -- a unique address for this app install on this device.
Send Token to Backend
The app sends this token to your backend right away, and again whenever it changes.
Backend Stores Token
The backend stores the token against that user's account, ready for future pushes.
To notify that user later, the backend does not contact the device directly -- it hands the token and a payload to a push service, delivery infrastructure the platform itself operates, which routes the message to the right device and surfaces it as a system notification or passes it straight to the running app.
A payload usually carries a title, a body, optional custom data such as an id used for a deep link, and delivery metadata.
Lock screens are public
Titles and bodies often render on a locked screen for anyone nearby to read -- never place an account balance, a diagnosis, or a one-time code directly in a visible notification.
React Native's own push-notification lesson covers framework-specific registration code; this lesson covers the architecture underneath any framework's implementation of it.
- Push Notification
- A message triggered by a server or service and delivered to a device through the platform's push infrastructure, even while the app is closed.
- Device Token
- A unique identifier a platform issues to one app installation on one device, used by a backend to target that install through the push service.
PUSH NOTIFICATION FLOW
----------------------
PUSH NOTIFICATION FLOW
-----------------------
DEVICE TOKEN REGISTRATION
Mobile App --> Register for Notifications
Mobile App --> Receive Device Token
Mobile App --> Send Token to Backend
Backend --> Stores Token (per user, per device)
SENDING A PUSH
Backend --> Push Service --> Device --> Mobile App / Notif.
(event happens) (platform delivery) (shown to the user)
LOCAL NOTIFICATION (no backend involved)
Mobile App --> Schedules Locally --> OS Delivers at Set TimeConnect it to a real scenario
Think through the full loop before writing any code. The app should ask for notification permission with context -- explaining why, ideally right before the moment it matters -- not as a blind prompt on first launch.
Once granted, the platform hands the app a device token, and the app's only job is to send that token to your backend right away, and again whenever it changes, since tokens can rotate after a reinstall or an OS update.
- Backend owns a table mapping user accounts to device tokens -- typically several tokens per user.
- When a notify-worthy event happens, the backend builds a payload and sends it to the push service per token.
- Keep the payload's data field small -- usually just a type and an id to route a tap to the right screen.
- Keep visible title/body generic for anything sensitive; fetch real detail after the user opens and authenticates.
Test on a real lock screen
Always check what actually renders on a real locked screen, not just what your code sends -- previews and rendering rules vary by platform and OS version.
Try the working example
function evaluateNotificationPayload(payload, context) {
if (!payload.containsSensitiveInfo) {
return { verdict: "safe", action: "show-as-is", reason: "No sensitive info in the payload." };
}
if (context.isLockScreen) {
return {
verdict: "unsafe",
action: "redact",
reason: "Sensitive info would render on the lock screen for anyone to see."
};
}
return {
verdict: "risky",
action: "redact-recommended",
reason: "Content also persists in the notification center after unlock, so redact by default."
};
}
const orderUpdate = {
title: "Order shipped",
body: "Your order is on its way!",
containsSensitiveInfo: false
};
const labResult = {
title: "New result from Dr. Lin",
body: "Your test came back positive for...",
containsSensitiveInfo: true
};
console.log("Order update:", evaluateNotificationPayload(orderUpdate, { isLockScreen: true }));
console.log("Lab result:", evaluateNotificationPayload(labResult, { isLockScreen: true }));The safe order-shipped notification returns { verdict: 'safe', action: 'show-as-is' } since it has no sensitive info. The lab-result notification returns { verdict: 'unsafe', action: 'redact', reason: 'Sensitive info would render on the lock screen for anyone to see.' } because it contains sensitive info and the context is a lock screen.5-minute try-it
Write a short spec for a notification your app might send (e.g. 'new comment on your post'). Decide exactly what goes in the visible title/body versus what stays in the data field for the app to fetch after opening. Then run the evaluateNotificationPayload-style function against it with isLockScreen true and confirm the verdict matches your design.
One important caution
Requesting notification permission immediately on first launch, before the user understands why, which drives permanent denials.
Putting real message content, account details, or codes directly in the payload's title/body instead of a generic placeholder.
Push technology - Wikipedia — How Mobile Apps Work