Managing Android Ongoing Notifications
Android ongoing notifications are experimental. The API may change in future releases.
Voltra supports Android ongoing notifications for local, app-driven status updates such as deliveries, rides, workouts, or timers.
Use this API when you want to:
- start a persistent notification from your app
- update its content over time
- stop it when the task ends
- add action buttons that open deep links in your app
Voltra also supports remote updates if your app receives push notifications in the background and forwards the payload to the ongoing notification APIs.
Server-side rendering support
Voltra already provides a server-side API for converting JSX into the semantic payload used by Android ongoing notifications.
Use these APIs only in server-side or backend code. Do not import them from your React Native app runtime.
Use voltra/android/server.
The main renderer APIs are:
renderAndroidOngoingNotificationPayloadToJson()returns an objectrenderAndroidOngoingNotificationPayload()returns a JSON string
This API only renders the payload. Your server still needs to send that payload through your push provider, and your app still needs a background task that calls upsertAndroidOngoingNotification() or stopAndroidOngoingNotification() when the push arrives.
Before you start
1. Enable notification manifest support
Add android.enableNotifications to the Voltra Expo plugin config:
This adds the Android manifest entries required by Voltra's notification features.
See Plugin Configuration for details.
2. Create a notification channel
channelId is required when starting an ongoing notification, and the channel must already exist.
If you use expo-notifications, you can create a channel like this:
3. Request notification permission on Android 13+
On Android 13 and above, posting notifications requires runtime permission.
4. If you want remote updates, register a background notification task
The playground app uses expo-notifications together with expo-task-manager to process real push notifications and update ongoing notifications in the background.
Register a background task early in app startup:
The example app does this during startup so that incoming pushes can update or stop an ongoing notification even when the app is backgrounded.
Starting a notification
Voltra provides two built-in layouts:
AndroidOngoingNotification.ProgressAndroidOngoingNotification.BigText
Progress notification
Big text notification
Updating a notification
Use the same notificationId to update an existing notification.
updateAndroidOngoingNotification() returns a result object. If the notification no longer exists, it returns reason: 'not_found' or reason: 'dismissed'.
Starting or updating with one call
If your app may re-enter the same flow multiple times, upsertAndroidOngoingNotification() can be easier than separate start/update logic.
This API is especially useful for remote updates, where the same incoming push may need to create the notification the first time and update it later.
Stopping a notification
To dismiss every active Voltra ongoing notification at once:
Hook API
For React screens and flows, use useAndroidOngoingNotification().
The hook returns:
start()update()end()isActive
Use autoStart to create the notification when the component mounts, and autoUpdate to refresh it when the JSX content changes.
Action buttons
You can add action buttons as children of Progress or BigText.
Action buttons currently:
- open the provided deep link
- can be used with
ProgressandBigText - support an optional
icon
Android may not show action icons in the standard notification UI, so treat them as optional enhancement rather than a guaranteed visual element.
Remote updates
Voltra can apply remote ongoing-notification updates if your app receives a push notification and handles it in a background task.
The end-to-end flow is:
- Your server renders Voltra JSX into an Android ongoing-notification payload.
- Your server sends a high-priority push notification.
- The push
datacontains avoltraOngoingNotificationobject. - Your background task parses that object.
- The task calls
upsertAndroidOngoingNotification()orstopAndroidOngoingNotification().
1. Render the payload on your server
Use renderAndroidOngoingNotificationPayloadToJson() when preparing a payload on your server or in app tooling:
Then send that payload inside a push message.
If your push provider expects strings for nested payload data, use renderAndroidOngoingNotificationPayload() instead and send the JSON string directly.
2. Send the payload through your push provider
The playground app expects data.voltraOngoingNotification to contain:
notificationId: the stable notification identifieroperation:'upsert'or'stop'options: start options such aschannelId,smallIcon,deepLinkUrl,requestPromotedOngoing, orfallbackBehaviorpayload: the Voltra semantic payload for'upsert'
Example Expo push request:
The playground app accepts either an object or a JSON string for data.voltraOngoingNotification. Stringifying it is often the safest option when sending through push providers.
To stop the notification remotely, send the same notificationId with operation: "stop" and omit payload.
3. Apply the payload in your background task
Channel setup for remote updates
Your background task should ensure that the target notification channel exists before calling upsertAndroidOngoingNotification(). The playground app creates the channel on startup and also ensures it exists again inside the background handler.
Important notes
- Voltra does include a server-side JSX-to-payload renderer for Android ongoing notifications.
- Remote updates depend on your push provider and app-level background notification setup.
- Voltra provides the ongoing-notification rendering and lifecycle APIs, but your app is responsible for receiving the push and invoking those APIs.
upsertAndroidOngoingNotification()is the easiest entry point for remote updates because it can create or update the notification with the same payload path.- If your push provider serializes nested objects as strings, parse
data.voltraOngoingNotificationbefore passing it to Voltra.
Main tap behavior
Use deepLinkUrl in the start or update options to control what happens when the user taps the main notification body:
This is separate from action button deep links.
Status and capability helpers
Use these helpers to adapt your UI to the device state:
Useful values include:
status.isActivestatus.isDismissedcapabilities.notificationsEnabledcapabilities.supportsPromotedNotificationscapabilities.canPostPromotedNotificationscapabilities.canRequestPromotedOngoing
Promoted ongoing notifications
If your app wants to request promoted ongoing presentation when the device supports it, pass requestPromotedOngoing: true:
You can also set fallbackBehavior if promoted presentation is unavailable:
Check device support first with getAndroidOngoingNotificationCapabilities() if you want to tailor the UX.
Current limitations
- Remote updates require your own push delivery and background task integration.
- Your app must create the Android notification channel before starting a notification.
- Notification permission still needs to be requested by your app on Android 13+.
- Action buttons open deep links. They are not a JavaScript event system.
