Documentation Index

Fetch the complete documentation index at: https://academy.insiderone.com/llms.txt

Use this file to discover all available pages before exploring further.

Configure Live Activities

Prev Next

SDK Version: 1.0.0 (InsiderLiveActivities)  |  Min iOS: 16.1 (17.2+ for register)

InsiderLiveActivities is a plugin built on top of iOS's ActivityKit framework that works integrated with the Insider infrastructure. For every Live Activity your app starts, it automatically captures the push-to-start and per-activity push tokens issued by Apple and forwards them to Insider. This lets you start and update your Live Activities through the Insider APIs.

How does it work?

ActivityKit reports two types of token for each Live Activity:

Token

When it is produced

What it is for

Stream

Push-to-Start Token

When the app first opens (after a device restart), 1 per device at the device level.

To start a Live Activity remotely (via the Insider API).

Activity<T>.pushToStartTokenUpdates (iOS 17.2+)

Per-Activity Push Token

When the activity is started with Activity.request(...), separately for each instance.

To update and end the ContentState of an existing Live Activity.

activity.pushTokenUpdates (iOS 16.1+)

The SDK listens to both streams and automatically forwards the tokens to the Insider infrastructure. On the customer end:

  1. Conform your ActivityAttributes type to InsiderLiveActivitiesAttributes.

  2. Call resumeActivities and (iOS 17.2+) register at app launch.

  3. Start the activity with Activity.request(...).

  4. Call cancel(activityId:) when the activity ends. This is not mandatory, because when an activity ends, the system does not produce a new token, and the SDK does not send a new request. If you want to turn off token tracking based on activity type or ID, you can use this feature.

Token management, retries, opt-in flags, and network security (encrypted request/response) are entirely handled within the SDK.

import ActivityKit
import InsiderMobile
import InsiderLiveActivities

// 1) ActivityAttributes - conform to the protocol.
@available(iOS 16.1, *)
struct OrderActivityAttributes: InsiderLiveActivitiesAttributes {
    let insiderLiveActivityId: InsiderLiveActivityIdentifier
    struct ContentState: Codable, Hashable {
        var minutesLeft: Int
    }
}

/**
  * 2) Inside AppDelegate.application(_:didFinishLaunchingWithOptions:),
  * AFTER Insider.initWithLaunchOptions(...) completes:
  */
Task {
    try? await Insider.liveActivities.resumeActivities(
        forType: Activity<OrderActivityAttributes>.self
    )
}

// 3) To be able to collect the activity push-to-start token inside any function
Task {
    if #available(iOS 17.2, *) {
        try? await Insider.liveActivities.register(
            forType: Activity<OrderActivityAttributes>.self
        )
    }
}

// 4) Starting an activity from inside a function:
let insiderIdentifier = InsiderLiveActivityIdentifier.custom("order-42")
_ = try Activity.request(
        attributes: OrderActivityAttributes(insiderLiveActivityId: insiderIdentifier),
        content: .init(state: .init(minutesLeft: 30), staleDate: nil),
        pushType: .token   // &larr; mandatory
    )


// 4) To stop tracking an activity:
await Insider.liveActivities.cancel(activityId: id) // ID Base
// OR
await Insider.liveActivities.cancel(forType: Activity<DeliveryActivityAttributes>.self) // Type Base
// OR
await Insider.liveActivities.cancelAll() // All Activities

Requirements

Requirement

Value

Minimum iOS

16.1 (module level)

register(forType:)

iOS 17.2+ (the push-to-start API arrived in this version)

Activity.request(attributes:content:pushType:)

iOS 16.2+ (on iOS 16.1 the variant with the contentState: parameter is used)

Insider Core SDK

InsiderMobile >= 15.1.0 must be initialized

Frameworks

Foundation, ActivityKit

Language

Swift (Objective-C not supported)

Info.plist

NSSupportsLiveActivities = true  (mandatory)

Info.plist (optional)

NSSupportsLiveActivitiesFrequentUpdates = true  (for heavy update scenarios)

APNs key

auth key in .p8 format - .p12/.pem are not supported

The Widget extension target, the App Group entitlement, and the ActivityConfiguration (SwiftUI) definition are entirely part of the Apple ActivityKit setup and are outside the scope of this document. Follow Apple's Displaying Live Data with Live Activities.

Live Activity permission is not the same thing as push notification permission. A user can opt out of push but stay opted in to Live Activity, or vice versa. There is no system prompt for Live Activity; it is on by default, and the user can turn it off using the Settings{app_name}Live Activities switch.

Dependency

pod 'InsiderLiveActivities', '1.0.0'
pod 'InsiderMobile', '15.1.0' // To be updated after release.
binary "https://mobilesdk.useinsider.com/carthage/InsiderLiveActivities/InsiderLiveActivities.json" == 1.0.0
binary "https://mobilesdk.useinsider.com/carthage/InsiderMobile/InsiderMobile.json" == 15.1.0 // To be updated after release.

SPM: Version 1.9.0

Integration

1. Define ActivityAttributes

Conform your ActivityAttributes type to the InsiderLiveActivitiesAttributes protocol and add an insiderLiveActivityId: InsiderLiveActivityIdentifier property.

import ActivityKit
import InsiderLiveActivities

@available(iOS 16.1, *)
struct OrderActivityAttributes: InsiderLiveActivitiesAttributes {
    // Read by Insider - the identity that defines the activity.
    let insiderLiveActivityId: InsiderLiveActivityIdentifier

    // Static content (defined by you).
    let orderId: String

    // Dynamic content.
    struct ContentState: Codable, Hashable {
        var minutesLeft: Int
        var status: String
    }
}

The insiderLiveActivityId property name must be exactly this; the SDK reads this field. If you give it another name or it is nil, the activity cannot be matched on the Insider side.

2. Register for Push-to-Start

If you want to start a Live Activity from the Insider panel, you need to collect the push-to-start token. You do this with register(forType:).

Task {
    if #available(iOS 17.2, *) {
        do {
            try await Insider.liveActivities.register(
                forType: Activity<OrderActivityAttributes>.self
            )
        } catch InsiderLiveActivitiesError.authorizationDenied {
            // The user has turned off Live Activities in Settings.
        } catch {
            // Other errors.
        }
    }
}

register(forType:) requires iOS 17.2+. Guard it with if #available(iOS 17.2, *); otherwise, you will get a compile-time error.

3. Start the activity

Starting the activity is the integrator's responsibility; the SDK does not start the activity; it only captures the token. The pushType: .token parameter in the Activity.request(...) call is required; otherwise, iOS does not produce a per-instance push token, and the SDK cannot forward updates to Insider One.

let id = InsiderLiveActivityIdentifier.custom("order-\(orderId)")
let attributes = OrderActivityAttributes(
    insiderLiveActivityId: id,
    orderId: orderId
)
let initialState = OrderActivityAttributes.ContentState(
    minutesLeft: 30,
    status: "preparing"
)

do {
    _ = try Activity.request(
        attributes: attributes,
        content: .init(state: initialState, staleDate: nil),
        pushType: .token   // &larr; mandatory
    )
} catch {
    // ActivityKit may throw: budget exceeded, OS rejection, etc.
}

insiderLiveActivityId must be unique for each activity. Starting more than one activity with the same ID overwrites the per-instance tokens on top of each other and causes confusion on the Insider side.

4. Resume (app relaunch)

To reconnect to the token stream of Live Activities that are still active when the app relaunches, call resumeActivities on every launch.

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // ... the Insider.initWithLaunchOptions(...) call must be made first

        Task {
            if #available(iOS 17.2, *) {
                do {
                    try? await Insider.liveActivities.resumeActivities(
                        forType: Activity<OrderActivityAttributes>.self
                    )
                } catch InsiderLiveActivitiesError.authorizationDenied {
                    // The user has turned off Live Activities in Settings.
                } catch {
                    // Other errors.
                }
            }
        }
        return true
    }
}

If resumeActivities is not called, the activity continues to be displayed by the system, but the SDK does not forward the refreshed push tokens to the Insider infrastructure.

5. Update the activity

The activity update is sent to APNs via the Insider API; you do not need to write any additional code on the mobile side. Since the SDK forwards the per-instance push token captured in Step 3 to Insider, the panel already knows "which activity to send the update to".

let insiderIdentifier = InsiderLiveActivityIdentifier.custom("order-\(orderId)")

insiderIdentifier.activityId // the key to be used for update in the API

6. End the activity

An activity can end in three ways:

  • From the inside, by an integrator call: You call the activity's Activity.end(...) yourself.

  • Through the Insider API, it sends an end push via APNs with the dismissal_date and the "end activity" signal.

  • Automatic OS behavior:

    • It drops from the Dynamic Island after 8 hours.

    • It drops from the lock screen after 12 hours.

    • The user can dismiss it manually.

API reference

Core types

InsiderLiveActivitiesAttributes

The protocol that the ActivityAttributes type you write must conform to.

@available(iOS 16.1, *)
public protocol InsiderLiveActivitiesAttributes: ActivityAttributes {
    var insiderLiveActivityId: InsiderLiveActivityIdentifier { get }
}

Member: insiderLiveActivityId
Type: InsiderLiveActivityIdentifier
Description: The identity that defines the activity on the Insider side. Created by the caller. The property name must be exactly this.

ActivityAttributes already requires Codable & Hashable and requires you to define a ContentState inside it; the SDK adds no additional constraints to these rules.

InsiderLiveActivityIdentifier

An identity-bound handle that represents the activity (activityId + insiderId + partnerName).

public struct InsiderLiveActivityIdentifier:
    RawRepresentable, Codable, Sendable, Hashable, Equatable, CustomStringConvertible

Public properties

Property

Type

Description

activityId

String

The ID given with .custom(_:) or the UUID generated with .auto.

insiderId

String

The Insider user ID captured at the moment the identifier was created.

partnerName

String

The partner short-code captured at the moment the identifier was created.

Factory methods

Factory

Description

.auto

A UUID-based identifier. Use it if you do not have an id specific to your domain.

.custom(_ id: String)

Produces an identifier with the id the caller provides (e.g. an order number). The uniqueness guarantee is on you.

// If you have a custom unique id you want to use
let id = InsiderLiveActivityIdentifier.custom("order-\(orderId)")

// If not
let id = InsiderLiveActivityIdentifier.auto

At the moment the identifier is created, it copies the Insider identity and the partner name into itself. If a user logs in/out, or you reinit at runtime, do not start an activity by reusing the old identifier for the new user; create a new identifier each time at the start of the activity.

Lifecycle methods

All methods are defined on Insider.liveActivities (i.e., InsiderLiveActivitiesProtocol) and are async and Sendable.

register(forType:)

@available(iOS 17.2, *)
func register<T: InsiderLiveActivitiesAttributes>(
    forType type: Activity<T>.Type
) async throws

This method starts listening to the push-to-start token stream (Activity<T>.pushToStartTokenUpdates) for the relevant activity type.

  • iOS 17.2+ required. Guard it with if #available(iOS 17.2, *).

  • You can use it inside any method at any time you want.

  • throws: InsiderLiveActivitiesError.authorizationDenied

    • If Live Activities is turned off in iOS Settings.

resumeActivities(forType:)

func resumeActivities<T: InsiderLiveActivitiesAttributes>(
    forType type: Activity<T>.Type
) async throws

This method reconnects to the pushTokenUpdates streams of the instances that are still active on Activity<T>.activities, and additionally starts listening to the activityUpdates stream for newly started instances.

  • iOS 16.1+.

  • Be sure to use this method inside didFinishLaunchOptions.

  • throws: InsiderLiveActivitiesError.authorizationDenied.

    • If Live Activities is turned off in iOS Settings.

cancel(forType:)

func cancel<T: InsiderLiveActivitiesAttributes>(
    forType type: Activity<T>.Type
) async

This method ends the type-level listener for the relevant activity type and drops all instance records of that type. Call it if you are turning off a feature entirely.

  • iOS 16.1+.

  • Does not throw.

cancel(activityId:)

func cancel(activityId: InsiderLiveActivityIdentifier) async

This method stops tracking a single activity instance and removes it from the internal cache. Call it when the activity ends.

  • iOS 16.1+.

  • Does not throw.

  • The activityId passed must exactly match the identifier you set in the insiderLiveActivityId field when starting the activity.

cancelAll()

func cancelAll() async

This method cancels all type-level and instance-level tracking tasks and clears the persisted push-opt-in cache. You can use it in GDPR opt-out, user logout, or account deletion scenarios.

  • iOS 16.1+.

  • Does not throw.

Error handling

@available(iOS 16.1, *)
public enum InsiderLiveActivitiesError: LocalizedError, Sendable {
    case authorizationDenied
}

Case: authorizationDenied
Trigger: ActivityAuthorizationInfo().areActivitiesEnabled == false
Description: The user has turned off the Settings{app_name}Live Activities switch. This is not the same thing as push permission.

do {
    try await Insider.liveActivities.register(
        forType: Activity<OrderActivityAttributes>.self
    )
} catch let error as InsiderLiveActivitiesError {
    switch error {
    case .authorizationDenied:
        // Direct the user to Settings or disable the feature.
        break
    }
} catch {
    // Other unexpected errors (e.g. cancellation).
}

Keep in mind

  • register(forType:) requires iOS 17.2+.

  • The pushType: .token parameter is mandatory in the Activity.request(...) call. Otherwise, the per-instance push token is not produced, and updates do not arrive.

  • The insiderLiveActivityId property name must be exactly this. Do not rename it or leave it optional nil.

  • insiderLiveActivityId must be unique for each activity. Starting more than one activity with the same ID mixes up the tokens.

  • If resumeActivities is not called on every app launch, tracking after a relaunch is silently lost. Call it inside didFinishLaunchingWithOptions.

  • cancel(activityId:) | cancel(forType:) | cancelAll() do not end the activity, they only stop the SDK tracking. To end the activity, use Activity.end(...) or a panel update.

  • At the moment the identifier is created, it copies the Insider ID and the partner name. Create the identifier right before starting the activity; do not reuse old identifiers for a new user or with a new partner.

  • iOS Live Activities drop from the Dynamic Island after 8 hours and from the lock screen after 12 hours. If you need a longer lifetime, plan your content stream accordingly.

Troubleshooting

The push-to-start token does not reach the Insider side

Check the following:

  • Was the register(forType:) call made? Is it running on an iOS 17.2+ device?

  • Did the Insider.initWithLaunchOptions(...) call complete before register? Tokens captured while Insider.getID() returns empty are dropped.

  • Is InsiderLiveActivitiesError.authorizationDenied being thrown? The user may have turned off Live Activity in Settings.

  • Do you see live activities in the logs? The token is printed in redacted form (first-4…last-4 (len=N)).

The activity does not start after push-to-start

  • Do the activity_attributes and content_state fields in the payload sent from the Insider panel match the structure of your ActivityAttributes/ContentState types on the Swift side exactly?

  • It may have hit the iOS Apple ActivityKit rate limit; check the device logs through Console.app with the process:liveactivitiesd filter.

Update pushes do not reach the activity

  • Was the pushType: .token parameter passed in the Activity.request(...) call?

  • If the app relaunched, was resumeActivities(forType:) called?

  • Is the activity still active? iOS automatically drops it after 8 hours on the Dynamic Island and 12 hours on the lock screen.

  • Is there a "throttled" error in the device liveactivitiesd logs? In heavy update scenarios, add the NSSupportsLiveActivitiesFrequentUpdates = true Info.plist key.

After user login/reinit, which user is the old activity written to?

  • The identifier is identity-bound, it contains insiderId and partnerName. After login/reinit, the existing activity or the new activities started via push-to-start are forwarded to the Insider infrastructure, grouped with the correct partner name and Insider ID.

  • To forward the push-to-start token and the opt-in values to the new user on login/reinit, you must call the register method again.

Push-to-start was triggered from the Insider panel while the app was killed, but there is no SDK tracking when the app opens

An activity started via push-to-start is resumed with the resumeActivities(forType:) call when the app opens. Make sure you always call resumeActivities in didFinishLaunchingWithOptions.

FAQ

Q: Do we need to call both register and resumeActivities?
A: Yes. The two cover different streams:

  • register → the iOS 17.2+ push-to-start stream (pushToStartTokenUpdates).

    • You can use this for users who you want to enable the push-to-start feature for; it is not mandatory.

  • resumeActivities → the iOS 16.1+ per-instance push token stream (activity.pushTokenUpdates).

    • You must use it in didFinishLaunchingWithOptions. On every launch, this tracks active activities and those about to start.

Q: Can we call it from Objective-C?
A: No. The module is Swift-only; async/await and the Activity<T> generics cannot support an Obj-C bridge.

Q: Can we use it from React Native/Flutter/hybrid frameworks?
A: Not directly. Because Apple ActivityKit requires Swift concurrency, generics, and SwiftUI, no ready-made JS/Dart convenience API can be provided. Use InsiderLiveActivities by writing Swift bridge code in your native modules.

Q: Is push notification permission the same thing as Live Activity permission?
A: No. A user can opt out of push but stay opted in to Live Activity, or vice versa. There is no iOS prompt for Live Activity; it is on by default, and the user can turn it off from the Settings{app_name}Live Activities switch. InsiderLiveActivitiesError.authorizationDenied is thrown only when this switch is off.

Q: Which platforms support it?
A: iOS 16.1+ and iPadOS 16.1+.

Q: What happens if we do not call cancel(activityId:)?
A: When the activity is ended by the OS, the ActivityKit streams close, and tracking ends naturally.

Q: Does register do anything on a freshly installed app?
A: Yes, but iOS can only produce the push-to-start token on the first open after the next device restart. It is normal if the token does not arrive after the first install; the token is produced the next time the user opens the device, and the SDK forwards it to Insider.

Q: We have a frequent update scenario. Will we get throttled?
A: Apple applies a budget limit on Live Activities. You can loosen this limit by adding the NSSupportsLiveActivitiesFrequentUpdates = true Info.plist key. Refer to this guide to determine the update frequency.

Demo project

GitHub - useinsider/SwiftDemo: Insider iOS SDKs Example