Push Notifications
A push notification is the little message that pops up on someone's phone. The ping you hear when WhatsApp gets a new message, the bubble that shows up when your favourite app has news.
Used well, push brings users back to your app. Used badly, your app gets muted and uninstalled. This page covers how to do it well.
The two rules of pushing
If you only remember two things from this page:
- Don't ask permission on launch. The very first time someone opens your app is the worst time to ask. Ask after they've experienced something good in your app. Completed an action, found value. Permission rates roughly double when you do this right.
- Send fewer, more meaningful pushes. A daily nudge is the ceiling for most apps. Anything more often than that and people start muting you.
Asking for permission the right way
"Ask for notification permission when the user completes their first habit, not at app launch. Show a small screen first explaining what we'll send (a gentle morning nudge, a celebration on streak milestones). Let them say no and ask again from settings later if they change their mind."
What that gives you:
- A friendly pre-prompt screen ("Hey, we'd love to send you a gentle morning nudge. Here's what we'd send and how often"). This isn't the system prompt, it's your own screen. After the user taps "Sure," we show the system prompt.
- A toggle in settings so users who said no can change their mind later.
- A respectful "we don't ask again unprompted" rule, so we don't pester.
Sending a notification
Two kinds:
- Local: scheduled by the phone itself. "Remind me at 9 AM tomorrow." No server needed.
- Remote: sent by your server when something happens. "User B got a comment from user A."
A typical remote-push setup:
"When user A comments on user B's post, send user B a push that says '[A] commented: [first 60 chars]'. Don't notify user A about their own comments. Tapping the notification opens the post detail screen."
What the agent can generate:
- Device-registration and token-storage code, plus review-first database setup.
- A narrow server send-function contract for the trigger event.
- Tap-through routing so the right screen opens after native notification setup is complete.
Receiving code does not need the Expo Push connector secret, but it still needs platform credentials, native configuration, and a development build. Sending uses an Expo access token that must never be bundled. Connect Expo Push so the build can validate integration metadata; then deploy the generated narrow relay and add a separate token directly to its secret manager. The saved connector token is not copied there.
What setup you still need to do
Unlike most features, push needs a little setup outside the app before notifications reach real devices. The agent walks you through these steps when you turn pushes on.
For iPhone
- In App Store Connect (Apple's dashboard), enable push for your app.
- Generate a special key (Apple calls it a
.p8key). - Upload it to Expo (the service that sends pushes for us). Expo's dashboard has a one-screen flow.
For Android
- Create a free Firebase project (or reuse one. See the Glossary).
- Add your Android app to that Firebase project.
- Download the configuration file (
google-services.json) and add it to your project. The agent handles the placement.
You then make and install a development build, deploy the send function, and give that runtime its own Expo access token. Appsanic does not run EAS, deploy the function, or copy the connector token into it.
You have to test on a real phone
Remote push notifications need a real device and a development or production build. Expo Go cannot receive remote notifications on Android from SDK 53 onward, and Appsanic does not trigger EAS builds for this setup. Export the project, create a development build, and test both receipt and tap-through on each target platform.
Pushing well. A short opinionated guide
The single biggest factor in whether users keep notifications on is whether the pushes are useful. Some patterns that work:
- Make each push actionable. Every push should have an obvious place it opens to.
- Respect quiet hours. Don't push at 3 AM unless the user specifically opted into that.
- Categorise. Don't bundle "your weekly summary," "your friend just posted," and "we have a sale" under one toggle. Let users keep the bits they want and turn off the rest.
"Add a Notifications panel to Settings. Users can toggle four categories independently: comments on their posts, mentions, weekly summaries, and marketing."
Things that go wrong (and how to spot them)
- A user revoked permission later. Always check at the moment you try to send. Don't assume an earlier "yes" still applies.
- Tokens expire. Phones occasionally invalidate their push registration. Re-register on each app launch.
- Badge counts get stuck. If you put a "5" badge on the app icon when a notification arrives, take it back off when the user views the content. Easy to forget.
- Pushes in low-power mode are delayed. Don't build features that need exact-minute delivery.
What about pushes to a web app?
Web push is a separate system (the Web Push Notification API). Most Appsanic apps are mobile-first, so we don't wire this up by default. If you have a web companion that also needs pushes, ask the agent. It can scaffold a parallel setup.
Going further: OneSignal
Expo Push covers the core job - register a device, store the token, send a push when an event fires. Once you're sending at real volume, you usually want more than raw delivery: who to send to, which message wins, and whether it actually landed. That's where OneSignal comes in.
OneSignal is a managed connector built for production push. It uses its own native SDK and routes through APNs/FCM rather than Expo's push gateway. It adds:
- Segmentation - target by user property, behaviour, or activity rather than sending to everyone.
- A/B testing - try two versions of a push against a slice of users and let the better one win.
- Delivery analytics - sent, delivered, opened, and converted, so you can see what's working instead of guessing.
OneSignal's App ID is publishable and safe to embed. Sending uses a separate secret REST API key and therefore needs a backend. Connect OneSignal from the connectors surface inside the relevant project, then ask:
"Move our push setup to OneSignal. Send the morning nudge only to users who haven't checked in today, and let me A/B test two versions of the streak-milestone message."
Start with Expo Push while you're finding your feet, and reach for OneSignal when targeting and measurement start to matter.
Under the hood (for engineers)
We use Expo Notifications, which abstracts over APNs and FCM. Server sends a request to https://exp.host/--/api/v2/push/send with one or more Expo push tokens.
Tokens look like ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx] and are safe to store in your database. They're scoped per-device-per-app and rotate when the user uninstalls.
Generated code can store tokens in a push_tokens table keyed to the user, but the SQL/RLS plan is review-first and must be applied before relying on it. A server function sends pushes when the relevant business event fires. Give that deployed function a separately provisioned Expo access token in its secret manager. The encrypted connector token is validation-only and is not transferred to runtime.
Next
You've got the core feature docs. Time to launch: read Previewing in Expo Go.
