Skip to content

Live Updates on Android

Pushwoosh supports Android Live Updates through the pushwoosh-liveupdates module (SDK 6.9.0 and later). A Live Update is an ongoing, progress-style notification that the system promotes on the lock screen, in the notification drawer, and as a status chip in the status bar, so users can follow an activity without opening your app.

The whole lifecycle is driven from the server: your backend sends a push when the activity starts, more pushes as it progresses, and a final push when it ends. The SDK renders each one automatically.

What are Live Updates

Anchor link to

Live Updates were introduced in Android 16 (API 36) as a way to surface a user-initiated, time-sensitive activity from start to finish. They build on the platform’s progress-centric notifications and Notification.ProgressStyle API. Conceptually they are the Android counterpart of iOS Live Activities.

This page covers the Pushwoosh integration only. For the platform behavior, promotion rules, and design guidance, see the official Android documentation:

When to use Live Updates

Anchor link to

Live Updates are meant for an activity that is ongoing, user-initiated, and time-sensitive — something with a clear start and end that the user actively cares about right now. Typical scenarios for Pushwoosh customers:

  • Food delivery — order accepted, being prepared, out for delivery, arriving.
  • Ride-hailing and taxi — driver assigned, en route, arriving, trip in progress.
  • Order and shipment tracking — live status of an order that is actively in transit.
  • Live sports and media — match score and time as the game unfolds.
  • Fitness — an active workout or run with elapsed time and progress.
  • Fintech — a transaction or verification flow moving through its stages.

Because the lifecycle is driven by real events that your backend already knows about (an order changes status, a courier moves), a Live Update is usually one API call wired into your existing event flow — not something a person sends by hand.

Requirements

Anchor link to
  • Android 16 (API 36) or newer. On older devices the module stays inactive and every Live Update API call is a safe no-op.
  • Pushwoosh Android SDK 6.9.0 or later.

Add the pushwoosh-liveupdates module

Anchor link to

Add the dependency to your app/build.gradle:

dependencies {
implementation 'com.pushwoosh:pushwoosh-liveupdates:<latest-version>'
}

Replace <latest-version> with the current version from Maven Central.

The module is discovered automatically at startup. It declares the required POST_PROMOTED_NOTIFICATIONS permission, registers its own notification channel, and intercepts Live Update pushes before the default notification path. There is no extra initialization code — the SDK sets the ongoing and promoted flags, downloads the large icon, maps action buttons, and posts the notification for you.

Send a Live Update

Anchor link to

You send Live Updates through Messaging API v2 by adding Live Update fields to the root_params object of the android content block. Use a transactional request — a Live Update targets the specific user whose activity it tracks. The schedule field is required; { "after": "0s" } sends immediately. The lifecycle has three operations, set in pw_live_op:

  • start — first push for an activity. Posts the ongoing notification.
  • update — a later push for the same activity. Refreshes it in place, silently.
  • end — terminal push. Dismisses the notification.

All pushes that belong to the same activity must share the same pw_live_id. That id ties the updates together and is also what you use to dismiss the update from the app.

Each push fully describes the notification — nothing carries over from the previous push. Resend every field you want to keep, such as the segments and the large icon, with each update; an omitted field is rendered as absent.

Live Update parameters

Anchor link to

These keys go inside the root_params object of the android content block. Title, body, and large icon use the standard Android push fields (title, body, custom_icon).

ParameterTypeDescription
pw_live_opstringLifecycle operation: start, update, or end. Required.
pw_live_idstringStable activity id shared by all pushes of one Live Update. Required.
pw_live_progressintProgress value, measured against the summed segment lengths.
pw_live_progress_indeterminateboolShow an indeterminate animation instead of a concrete value.
pw_live_segmentsJSON stringOrdered progress segments, each {"color": "#RRGGBB", "length": N}.
pw_live_extrasJSON stringArbitrary data passed through to a custom style provider.
pw_live_whenlongHeader time anchor, in epoch milliseconds.
pw_live_chronometerboolShow the header time as a running timer.
pw_live_chronometer_count_downboolA running timer counts down instead of up.
pw_live_show_whenboolShow the header time column at all. Defaults to true.

The four time fields combine as follows: with pw_live_show_when set to false the time is hidden; otherwise pw_live_when is the anchor, pw_live_chronometer turns it into a live counter, and pw_live_chronometer_count_down makes that counter run backwards.

Start push

Anchor link to
Terminal window
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
-H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transactional": {
"application": "XXXXX-XXXXX",
"platforms": ["ANDROID"],
"users": { "list": ["customer-42"] },
"payload": {
"content": {
"localized_content": {
"default": {
"android": {
"title": "Order #4521",
"body": "We are preparing your order",
"custom_icon": "https://example.com/restaurant.png",
"root_params": {
"pw_live_op": "start",
"pw_live_id": "order_4521",
"pw_live_progress": "1",
"pw_live_segments": "[{\"color\":\"#34A853\",\"length\":3},{\"color\":\"#FBBC05\",\"length\":4},{\"color\":\"#4285F4\",\"length\":3}]",
"pw_live_extras": "{\"eta\":\"18:40\"}"
}
}
}
}
}
},
"schedule": { "after": "0s" },
"message_type": "MESSAGE_TYPE_TRANSACTIONAL"
}
}'

Update push

Anchor link to

Send an update with the same pw_live_id whenever the activity moves forward. Repeat the segments and the icon — an update that omits them renders without them.

Terminal window
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
-H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transactional": {
"application": "XXXXX-XXXXX",
"platforms": ["ANDROID"],
"users": { "list": ["customer-42"] },
"payload": {
"content": {
"localized_content": {
"default": {
"android": {
"title": "Order #4521",
"body": "Your courier is on the way",
"custom_icon": "https://example.com/restaurant.png",
"root_params": {
"pw_live_op": "update",
"pw_live_id": "order_4521",
"pw_live_progress": "7",
"pw_live_segments": "[{\"color\":\"#34A853\",\"length\":3},{\"color\":\"#FBBC05\",\"length\":4},{\"color\":\"#4285F4\",\"length\":3}]"
}
}
}
}
}
},
"schedule": { "after": "0s" },
"message_type": "MESSAGE_TYPE_TRANSACTIONAL"
}
}'

The terminal push only needs the operation and the id.

Terminal window
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
-H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transactional": {
"application": "XXXXX-XXXXX",
"platforms": ["ANDROID"],
"users": { "list": ["customer-42"] },
"payload": {
"content": {
"localized_content": {
"default": {
"android": {
"root_params": {
"pw_live_op": "end",
"pw_live_id": "order_4521"
}
}
}
}
}
},
"schedule": { "after": "0s" },
"message_type": "MESSAGE_TYPE_TRANSACTIONAL"
}
}'

Customize the appearance

Anchor link to

The SDK ships a default progress style built from pw_live_progress, pw_live_progress_indeterminate, and pw_live_segments. To take full control of the progress bar, implement LiveUpdateProgressStyleProvider and shape a Notification.ProgressStyle yourself.

The provider is the single customization point. The SDK still owns channel setup, the ongoing and promoted flags, the large icon, action buttons, and the header time — a custom provider can only shape the progress bar, so it cannot break promotion eligibility. It must be stateless: derive the returned style only from the supplied LiveUpdateState. If it throws, the SDK falls back to the default style and the notification still posts.

import android.app.Notification;
import androidx.annotation.NonNull;
import com.pushwoosh.liveupdates.LiveUpdateProgressStyleProvider;
import com.pushwoosh.liveupdates.LiveUpdateSegment;
import com.pushwoosh.liveupdates.LiveUpdateState;
import java.util.List;
public class OrderStyleProvider implements LiveUpdateProgressStyleProvider {
@NonNull
@Override
public Notification.ProgressStyle createStyle(@NonNull LiveUpdateState state) {
Notification.ProgressStyle style = new Notification.ProgressStyle();
if (state.getProgress() != null) {
style.setProgress(state.getProgress());
}
style.setProgressIndeterminate(state.isProgressIndeterminate());
List<LiveUpdateSegment> segments = state.getSegments();
int boundary = 0;
for (int i = 0; i < segments.size(); i++) {
LiveUpdateSegment seg = segments.get(i);
style.addProgressSegment(
new Notification.ProgressStyle.Segment(seg.getLength()).setColor(seg.getColor()));
boundary += seg.getLength();
if (i < segments.size() - 1) {
style.addProgressPoint(new Notification.ProgressStyle.Point(boundary));
}
}
return style;
}
}

Register the provider with a <meta-data> tag in AndroidManifest.xml. The class must have a public no-argument constructor.

<meta-data
android:name="com.pushwoosh.LIVE_UPDATE_STYLE_PROVIDER"
android:value="com.example.OrderStyleProvider" />

Use LiveUpdateState.getExtras() to read the JSON you sent in pw_live_extras and adapt the style to your own business data.

Manage Live Updates from your app

Anchor link to

The server drives every start, update, and end, so there is no app-side API to post or refresh a Live Update. The PushwooshLiveUpdates facade covers only what the server cannot do — dismissing an update locally and checking which ones are on screen.

import com.pushwoosh.liveupdates.PushwooshLiveUpdates;
// Dismiss a specific Live Update when the user finishes the activity in-app,
// without waiting for the server's terminal "end" push
PushwooshLiveUpdates.endLiveUpdate("order_4521");
// List the activity ids currently shown by this app
List<String> active = PushwooshLiveUpdates.getActiveIds();
// Clear everything this app is showing, for example on logout
PushwooshLiveUpdates.endAllLiveUpdates();

All methods are safe to call from any thread and are a no-op on devices below Android 16.

Anchor link to