> This page is part of the [Customer.io documentation](https://docs.customer.io). For the complete index, see [llms.txt](https://docs.customer.io/llms.txt).
> Last updated: August 19, 2026

# Set up live notifications

## How it works

Live notifications show information that changes over time in places your customers already look: the iOS Lock Screen and the Android notification panel. On iOS they’re built on Apple’s Live Activities; on Android, they’re built on Google’s Live Updates.

The Flutter SDK includes two built-in templates that both native SDKs render for you—a multi-step tracker and a countdown timer—so you don’t need to write a platform-specific UI for either one. You can also define a single custom type and render it yourself.

Four actors drive every live notification:

*   **You** enable the notification types your app uses, and start notifications from Dart when something happens in your app.
*   **The SDK** registers the push tokens each notification needs. It also reports to Customer.io when your app starts or ends a notification, and when a customer dismisses one. Updates your app makes on the device aren’t reported.
*   **Your server** starts, updates, and ends notifications by calling [the API](/integrations/api/app/#tag/live-notifications). It never talks to APNs or FCM directly.
*   **Customer.io** turns each API call into a push, using the tokens the SDK registered, and records every start, update, and end as a delivery.

For the concepts behind the feature and the operations your server calls, see the [live notifications overview](/messaging/channels/live-notifications/overview/).

## Prerequisites

Live notifications use the push credentials your app already has in Customer.io. Before you begin:

*   Set up [push notifications](/integrations/sdk/flutter/push-notifications/push-setup/) for your app.
*   You must identify your app user before you can start a notification. The SDK holds token registrations until you identify a person, and [the API](/integrations/api/app/#tag/live-notifications/startLiveNotification) rejects requests that target anonymous profiles.
*   On iOS, target **iOS 16.2 or later**. Starting a notification from your server (push-to-start) requires iOS 17.2.
*   On Android, request `POST_NOTIFICATIONS` on Android 13 and later. To get Android 16’s promoted **Live Updates** treatment, also declare `POST_PROMOTED_NOTIFICATIONS` in your manifest. Without it, live notifications still render as ongoing notifications.

## Set up your Android project

You don’t need to do any build-time setup on Android. Live notifications are part of the push module, so they’re available as soon as you [configure them in your `CustomerIOConfig`](#initialize-the-sdk-with-live-notifications).

## Set up your iOS project

To support iOS, you need to enable the Live Activities module, add a widget extension to render your notifications, and forward widget URLs to the SDK so taps are attributed.

### Enable the Live Activities module

Live notifications are opt-in on iOS.

CocoaPodsSPM

#### CocoaPods

Add the `liveactivities` subspec to your Podfile. Open `ios/Podfile` in your Flutter project and add the following line alongside your existing `customer_io` pod:

```
pod 'customer_io/liveactivities', :path => '.symlinks/plugins/customer_io/ios'
```

#### SPM

Add the following property to your project’s `android/gradle.properties` file. Despite the location, this flag controls the iOS build too:

```
customerio_live_activities_enabled=true
```

If the flag isn’t detected (for example, in Flutter add-to-app modules or some CI environments), set the `CIO_LIVE_ACTIVITIES` environment variable instead:

```
CIO_LIVE_ACTIVITIES=true flutter build ios
```

Then set `NSSupportsLiveActivities` in `ios/Runner/Info.plist`. Without it, iOS refuses to start any notification, so nothing appears even when everything else is configured:

```
<key>NSSupportsLiveActivities</key>
<true/>
```

### Add a widget extension

iOS renders live notifications from a widget extension, so your app needs one even when you only use the built-in templates. In Xcode, choose **File > New > Target > Widget Extension**.

A widget extension can’t link the Flutter plugin pod, so name the rendering pods in its own Podfile target. Keep the version in step with the native iOS SDK version the plugin pins, which you’ll find as `native_sdk_version` in the plugin’s `pubspec.yaml`:

```
target 'LiveActivityWidget' do
  use_frameworks!
  pod 'CustomerIOLiveActivitiesTemplates', '4.7.2'
  pod 'CustomerIOLiveActivitiesAttributes', '4.7.2'
end
```

That pin is the native version the wrapper ships with today. Read yours before you copy it—an extension built against a different native SDK than your app can fail to link.

Then add the SDK’s built-in widgets to your extension’s `WidgetBundle`. Both ship in `CioLiveActivities_Templates`:

```
import CioLiveActivities_Templates
import SwiftUI
import WidgetKit

@main
struct LiveActivityWidgetBundle: WidgetBundle {
  var body: some Widget {
    CIOSegmentsLiveActivity()
    CIOCountdownTimerLiveActivity()
  }
}
```

List only the widgets for the templates you enabled.

### Forward widget URLs to the SDK

When someone taps a live notification, iOS opens your app with the widget URL. Forward it to the SDK from your `AppDelegate` to attribute the tap to the notification:

```
import customer_io

override func application(_ app: UIApplication, open url: URL,
                          options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
  guard let routableUrl = CustomerIOLiveActivities.handleWidgetUrl(url) else { return true }
  return super.application(app, open: routableUrl, options: options)
}
```

`handleWidgetUrl` reports the `opened` metric and returns the URL to route to. A URL that didn’t come from Customer.io comes back unchanged. `nil` means the notification did not contain a deep link, so there’s nothing to open. Android needs no equivalent step.

## Initialize the SDK with live notifications

Add a `liveNotificationsConfig` to your `CustomerIOConfig`, listing the built-in types your app uses:

```
CustomerIO.initialize(
  config: CustomerIOConfig(
    cdpApiKey: 'your-cdp-api-key',
    liveNotificationsConfig: LiveActivitiesConfig(
      types: [
        LiveActivityTemplate.segments,
        LiveActivityTemplate.countdownTimer,
      ],
    ),
  ),
);
```

Enabling a type registers it for push-to-start, so your server can create that notification remotely. Unrecognized identifiers are ignored, so a template added in a newer native SDK won’t break an older build of your app.

Option

Type

Default

Description

`types`

`List<LiveActivityTemplate>`

`[]`

Built-in templates to enable. Don’t list `custom` here—`customType` enables it.

`customType`

`String?`

`null`

Reverse-DNS identifier for your own type, such as `com.myapp.rideshare`.

`branding`

`LiveActivitiesBranding?`

`null`

Styling for the built-in templates. Android only.

### Branding on Android

Android renders Customer.io’s built-in templates itself, so you can pass a `branding` object to customize their appearance. iOS ignores it, because your widget extension’s SwiftUI defines the appearance there.

```
liveNotificationsConfig: LiveActivitiesConfig(
  types: [LiveActivityTemplate.segments],
  branding: LiveActivitiesBranding(
    accentColorHex: '#1B5E20',
    logoResource: 'brand_logo',
    smallIconResource: 'ic_notification',
  ),
),
```

`logoResource` and `smallIconResource` name bundled Android drawable resources. You can use `logoUrl` for a remote logo instead, but a bundled resource renders on the first frame without a network round-trip.

## Render a custom type

To send data that Customer.io’s built-in templates don’t support by default, you can name your own type with `customType` and render it on both platforms yourself:

```
liveNotificationsConfig: LiveActivitiesConfig(
  types: [LiveActivityTemplate.segments],
  customType: 'com.myapp.rideshare',
),
```

Then start it with `LiveActivityPayload.custom`. On each platform, you need to render the notification:

*   **iOS**: render the SDK’s `CIOCustomAttributes` in your widget extension with your own SwiftUI.
*   **Android**: implement `createLiveNotification` in a `CustomerIOLiveNotificationsCallback` and register it with `CustomerIOLiveActivities.setLiveNotificationCallback`. Register it in `Application.onCreate`, before `CustomerIO.initialize` runs—the native SDK only accepts the callback at build time, and a push can start your process with no Activity. Your callback receives the same `data` map as the one you pass to `start`.

[GitHub project](https://github.com/customerio/customerio-flutter "View the Flutter SDK on GitHub")

Version

4.2.1 (Current)2.x (2.9.0)1.x (1.5.2)

©2026 Peaberry Software, Inc. [Status](https://status.customerio.com/) [Terms of Service](https://customer.io/legal/terms-of-service/) [Privacy Policy](https://customer.io/legal/privacy-policy/)

[](https://www.linkedin.com/company/customer-io)[](https://twitter.com/customerio)[](https://www.youtube.com/channel/UCkCaWdezRoa8ZyR9pEVaipA)[](https://www.instagram.com/customer.io/)
