Manage iOS Live Activities from Capacitor with a powerful JSON-based layout system.
- iOS 16.1+ Live Activities - Full integration with Apple's Live Activities framework
- Dynamic Island Support - Seamless integration with iPhone 14 Pro+ Dynamic Island
- JSON Layout System - Build complex layouts declaratively without Swift code
- Real-time Updates - Update your activities dynamically from your app
- Image Management - Save and use images in your Live Activities via App Groups
- Cross-platform Safe - Graceful fallbacks on Android and web
Essential for delivery tracking apps, sports scores, ride-sharing, timers, and any app needing real-time lock screen updates.
The most complete doc is available here: https://capgo.app/docs/plugins/live-activities/
| Plugin version | Capacitor compatibility | Maintained |
|---|---|---|
| v8.*.* | v8.*.* | ✅ |
| v7.*.* | v7.*.* | On demand |
| v6.*.* | v6.*.* | ❌ |
| v5.*.* | v5.*.* | ❌ |
Note: The major version of this plugin follows the major version of Capacitor. Use the version that matches your Capacitor installation (e.g., plugin v8 for Capacitor 8). Only the latest major version is actively maintained.
bun add @capgo/capacitor-live-activities
bunx cap sync- iOS 16.1+ - Live Activities require iOS 16.1 or later
- Widget Extension - You must create a Widget Extension target in Xcode
- App Groups - Required for sharing data between app and widget
In Xcode:
- File → New → Target
- Select "Widget Extension"
- Name it exactly:
LiveActivities - Uncheck "Include Configuration Intent"
- Select your main app target → Signing & Capabilities
- Add "App Groups" capability
- Create group:
group.YOUR_BUNDLE_ID.liveactivities - Add the same App Group to your Widget Extension target
Add to your app's Info.plist:
<key>NSSupportsLiveActivities</key>
<true/>In your Widget Extension, create LiveActivitiesBundle.swift:
import WidgetKit
import SwiftUI
@main
struct LiveActivitiesBundle: WidgetBundle {
var body: some Widget {
// Your Live Activity widget goes here
LiveActivityWidget()
}
}import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const checkSupport = async () => {
const { supported, reason } = await CapgoLiveActivities.areActivitiesSupported();
if (supported) {
console.log('Live Activities are supported!');
} else {
console.log('Not supported:', reason);
}
};import { CapgoLiveActivities } from '@capgo/capacitor-live-activities';
const startDeliveryActivity = async () => {
const { activityId } = await CapgoLiveActivities.startActivity({
layout: {
type: 'container',
direction: 'vertical',
spacing: 8,
children: [
{
type: 'container',
direction: 'horizontal',
children: [
{ type: 'image', source: 'sfSymbol', value: 'box.truck.fill', width: 24, height: 24, tintColor: '#007AFF' },
{ type: 'text', content: 'Order #{{orderNumber}}', fontSize: 16, fontWeight: 'bold' }
]
},
{ type: 'text', content: '{{status}}', fontSize: 14, color: '#666666' },
{ type: 'progress', value: 'progress', tint: '#34C759' }
]
},
dynamicIslandLayout: {
expanded: {
leading: { type: 'image', source: 'sfSymbol', value: 'box.truck.fill', tintColor: '#007AFF' },
trailing: { type: 'text', content: '{{eta}}', fontWeight: 'semibold' },
center: { type: 'text', content: '{{status}}', fontSize: 14 },
bottom: { type: 'progress', value: 'progress', tint: '#34C759' }
},
compactLeading: { type: 'image', source: 'sfSymbol', value: 'box.truck.fill' },
compactTrailing: { type: 'text', content: '{{eta}}' },
minimal: { type: 'image', source: 'sfSymbol', value: 'box.truck.fill' }
},
behavior: {
widgetUrl: 'myapp://order/12345'
},
data: {
orderNumber: '12345',
status: 'On the way',
eta: '10 min',
progress: 0.6
}
});
console.log('Started activity:', activityId);
return activityId;
};const updateActivity = async (activityId: string) => {
await CapgoLiveActivities.updateActivity({
activityId,
data: {
status: 'Arriving soon!',
eta: '2 min',
progress: 0.9
},
alertConfiguration: {
title: 'Delivery Update',
body: 'Your order is almost there!'
}
});
};const endActivity = async (activityId: string) => {
await CapgoLiveActivities.endActivity({
activityId,
data: {
status: 'Delivered!',
progress: 1.0
},
dismissalPolicy: 'after',
dismissAfter: Date.now() + 3600000 // Keep visible for 1 hour
});
};const startTimerActivity = async () => {
const targetDate = Date.now() + 1800000; // 30 minutes from now
const { activityId } = await CapgoLiveActivities.startActivity({
layout: {
type: 'container',
direction: 'horizontal',
spacing: 16,
children: [
{ type: 'image', source: 'sfSymbol', value: 'timer', width: 32, height: 32 },
{
type: 'container',
direction: 'vertical',
children: [
{ type: 'text', content: '{{title}}', fontSize: 16, fontWeight: 'bold' },
{ type: 'timer', targetDate: 'endTime', style: 'timer', fontSize: 24, fontWeight: 'bold', color: '#FF3B30' }
]
}
]
},
dynamicIslandLayout: {
expanded: {
center: { type: 'text', content: '{{title}}' },
bottom: { type: 'timer', targetDate: 'endTime', style: 'timer', fontSize: 32 }
},
compactLeading: { type: 'image', source: 'sfSymbol', value: 'timer' },
compactTrailing: { type: 'timer', targetDate: 'endTime', style: 'timer' },
minimal: { type: 'timer', targetDate: 'endTime', style: 'timer' }
},
data: {
title: 'Cooking Timer',
endTime: targetDate
}
});
return activityId;
};// Save an image first
const { imageName } = await CapgoLiveActivities.saveImage({
imageData: 'base64EncodedImageData...',
name: 'product-thumbnail',
compressionQuality: 0.8
});
// Use in activity layout
const { activityId } = await CapgoLiveActivities.startActivity({
layout: {
type: 'container',
direction: 'horizontal',
children: [
{ type: 'image', source: 'saved', value: imageName, width: 48, height: 48, properties: { cornerRadius: 8 } },
{ type: 'text', content: '{{productName}}', fontSize: 16 }
]
},
// ... rest of config
});
// Cleanup when done
await CapgoLiveActivities.cleanupImages();Groups child elements horizontally, vertically, or stacked.
{
type: 'container',
direction: 'horizontal' | 'vertical' | 'zstack',
alignment: 'leading' | 'center' | 'trailing' | 'top' | 'bottom',
spacing: 8,
children: [/* ... */],
properties: { padding: 12, backgroundColor: '#F5F5F5', cornerRadius: 8 }
}Displays text with styling and variable interpolation.
{
type: 'text',
content: 'Hello {{name}}!',
fontSize: 16,
fontWeight: 'bold',
color: '#000000',
alignment: 'center',
lineLimit: 2,
fontDesign: 'rounded'
}Displays images from various sources.
// SF Symbol
{ type: 'image', source: 'sfSymbol', value: 'star.fill', tintColor: '#FFD700' }
// URL
{ type: 'image', source: 'url', value: 'https://example.com/image.png', width: 48, height: 48 }
// Saved image
{ type: 'image', source: 'saved', value: 'my-saved-image' }
// Asset from bundle
{ type: 'image', source: 'asset', value: 'logo' }Shows a progress bar.
{
type: 'progress',
value: 'progressValue', // Key in data object (0-1)
tint: '#34C759'
}Displays a countdown or elapsed time.
{
type: 'timer',
targetDate: 'endTime', // Key in data object (timestamp)
style: 'timer' | 'relative' | 'offset',
fontSize: 24,
color: '#FF3B30',
pausesOnReach: true
}Circular progress indicator.
{
type: 'gauge',
value: 'level', // Key in data (0-1)
style: 'accessoryCircular',
label: 'Battery',
tint: '#34C759'
}Flexible space between elements.
{ type: 'spacer', minLength: 8 }areActivitiesSupported()startActivity(...)updateActivity(...)endActivity(...)getAllActivities()saveImage(...)removeImage(...)listImages()cleanupImages()getPluginVersion()startTimerSequence(...)pauseTimerSequence(...)resumeTimerSequence(...)stopTimerSequence(...)skipTimerStep(...)previousTimerStep(...)getTimerState(...)addListener('timerSequenceEvent', ...)- Interfaces
- Type Aliases
Capacitor Live Activities Plugin interface for managing iOS Live Activities.
areActivitiesSupported() => Promise<AreActivitiesSupportedResult>Check if Live Activities are supported on this device. Requires iOS 16.1+ and device support.
Returns: Promise<AreActivitiesSupportedResult>
Since: 1.0.0
startActivity(options: StartActivityOptions) => Promise<StartActivityResult>Start a new Live Activity with the specified layout and data.
| Param | Type | Description |
|---|---|---|
options |
StartActivityOptions |
- Options for starting the activity |
Returns: Promise<StartActivityResult>
Since: 1.0.0
updateActivity(options: UpdateActivityOptions) => Promise<void>Update an existing Live Activity with new data.
| Param | Type | Description |
|---|---|---|
options |
UpdateActivityOptions |
- Options for updating the activity |
Since: 1.0.0
endActivity(options: EndActivityOptions) => Promise<void>End a Live Activity.
| Param | Type | Description |
|---|---|---|
options |
EndActivityOptions |
- Options for ending the activity |
Since: 1.0.0
getAllActivities() => Promise<GetAllActivitiesResult>Get all currently active Live Activities.
Returns: Promise<GetAllActivitiesResult>
Since: 1.0.0
saveImage(options: SaveImageOptions) => Promise<SaveImageResult>Save an image to the shared App Group container for use in Live Activities. Images must be saved to the shared container to be accessible from the widget extension.
| Param | Type | Description |
|---|---|---|
options |
SaveImageOptions |
- Options for saving the image |
Returns: Promise<SaveImageResult>
Since: 1.0.0
removeImage(options: RemoveImageOptions) => Promise<RemoveImageResult>Remove a saved image from the shared container.
| Param | Type | Description |
|---|---|---|
options |
RemoveImageOptions |
- Options for removing the image |
Returns: Promise<RemoveImageResult>
Since: 1.0.0
listImages() => Promise<ListImagesResult>List all saved images in the shared container.
Returns: Promise<ListImagesResult>
Since: 1.0.0
cleanupImages() => Promise<void>Remove all saved images from the shared container.
Since: 1.0.0
getPluginVersion() => Promise<{ version: string; }>Get the native Capacitor plugin version.
Returns: Promise<{ version: string; }>
Since: 1.0.0
startTimerSequence(options: TimerSequenceOptions) => Promise<TimerSequenceResult>Start a timer sequence for workouts/sports. On iOS: Shows in Live Activity and Dynamic Island On Android: Shows as a foreground notification with timer
| Param | Type | Description |
|---|---|---|
options |
TimerSequenceOptions |
- Timer sequence configuration |
Returns: Promise<TimerSequenceResult>
Since: 1.0.0
pauseTimerSequence(options: { sequenceId: string; }) => Promise<void>Pause the timer sequence.
| Param | Type | Description |
|---|---|---|
options |
{ sequenceId: string; } |
- Options containing the sequence ID |
Since: 1.0.0
resumeTimerSequence(options: { sequenceId: string; }) => Promise<void>Resume a paused timer sequence.
| Param | Type | Description |
|---|---|---|
options |
{ sequenceId: string; } |
- Options containing the sequence ID |
Since: 1.0.0
stopTimerSequence(options: { sequenceId: string; }) => Promise<void>Stop and dismiss the timer sequence.
| Param | Type | Description |
|---|---|---|
options |
{ sequenceId: string; } |
- Options containing the sequence ID |
Since: 1.0.0
skipTimerStep(options: { sequenceId: string; }) => Promise<void>Skip to the next step in the sequence.
| Param | Type | Description |
|---|---|---|
options |
{ sequenceId: string; } |
- Options containing the sequence ID |
Since: 1.0.0
previousTimerStep(options: { sequenceId: string; }) => Promise<void>Go back to the previous step in the sequence.
| Param | Type | Description |
|---|---|---|
options |
{ sequenceId: string; } |
- Options containing the sequence ID |
Since: 1.0.0
getTimerState(options: GetTimerStateOptions) => Promise<TimerSequenceState>Get the current state of a timer sequence.
| Param | Type | Description |
|---|---|---|
options |
GetTimerStateOptions |
- Options containing the sequence ID |
Returns: Promise<TimerSequenceState>
Since: 1.0.0
addListener(eventName: 'timerSequenceEvent', callback: TimerSequenceCallback) => Promise<{ remove: () => Promise<void>; }>Add a listener for timer sequence events. Events include: stepChange, complete, tick, paused, resumed, stopped, loopComplete
| Param | Type | Description |
|---|---|---|
eventName |
'timerSequenceEvent' |
- The event name to listen for |
callback |
TimerSequenceCallback |
- Callback function that receives the event |
Returns: Promise<{ remove: () => Promise<void>; }>
Since: 1.0.0
Result of checking if activities are supported
| Prop | Type | Description |
|---|---|---|
supported |
boolean |
Whether Live Activities are supported on this device |
reason |
string |
Reason if not supported |
Result of starting an activity
| Prop | Type | Description |
|---|---|---|
activityId |
string |
Unique activity identifier |
Options for starting a Live Activity
| Prop | Type | Description |
|---|---|---|
layout |
ActivityLayout |
Main activity layout (lock screen widget) |
dynamicIslandLayout |
DynamicIslandLayout |
Dynamic Island layout configuration |
behavior |
LiveActivitiesBehavior |
Activity behavior settings |
data |
Record<string, unknown> |
Dynamic data for the activity |
staleDate |
number |
Stale date timestamp (activity becomes stale after this) |
relevanceScore |
number |
Relevance score for activity ordering (0-100) |
Container layout element for grouping child elements
| Prop | Type | Description |
|---|---|---|
type |
'container' |
|
direction |
'horizontal' | 'vertical' | 'zstack' |
Layout direction |
children |
LayoutElement[] |
Child elements |
alignment |
'leading' | 'center' | 'trailing' | 'top' | 'bottom' |
Alignment within container |
spacing |
number |
Spacing between children |
properties |
BaseLayoutProperties |
Container properties |
Base layout element properties
| Prop | Type | Description |
|---|---|---|
padding |
number | { top?: number; bottom?: number; leading?: number; trailing?: number; } |
Padding around the element |
backgroundColor |
ColorString |
Background color |
cornerRadius |
number |
Corner radius |
width |
number | 'infinity' |
Frame width |
height |
number |
Frame height |
opacity |
number |
Opacity (0-1) |
Text layout element
| Prop | Type | Description |
|---|---|---|
type |
'text' |
|
content |
string |
Text content - supports {{variable}} interpolation |
fontSize |
number |
Font size |
fontWeight |
'ultraLight' | 'thin' | 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'heavy' | 'black' |
Font weight |
color |
ColorString |
Text color |
alignment |
'leading' | 'center' | 'trailing' |
Text alignment |
lineLimit |
number |
Line limit |
fontDesign |
'default' | 'monospaced' | 'rounded' | 'serif' |
Font design |
properties |
BaseLayoutProperties |
Element properties |
Image layout element
| Prop | Type | Description |
|---|---|---|
type |
'image' |
|
source |
'url' | 'sfSymbol' | 'asset' | 'base64' | 'saved' |
Image source type |
value |
string |
Image value (URL, symbol name, asset name, base64 string, or saved image name) |
width |
number |
Image width |
height |
number |
Image height |
contentMode |
'fit' | 'fill' |
Content mode |
tintColor |
ColorString |
Tint color for SF Symbols |
properties |
BaseLayoutProperties |
Element properties |
Progress bar layout element
| Prop | Type | Description |
|---|---|---|
type |
'progress' |
|
value |
string | number |
Progress value key in data (0-1) or direct value |
total |
string | number |
Total value key in data or direct value |
tint |
ColorString |
Progress bar color |
properties |
BaseLayoutProperties |
Element properties |
Timer layout element for countdowns
| Prop | Type | Description |
|---|---|---|
type |
'timer' |
|
targetDate |
string | number |
Target date key in data or timestamp |
style |
'timer' | 'relative' | 'offset' |
Timer style |
pausesOnReach |
boolean |
Pause when target reached |
fontSize |
number |
Font size |
color |
ColorString |
Text color |
fontWeight |
'ultraLight' | 'thin' | 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'heavy' | 'black' |
Font weight |
properties |
BaseLayoutProperties |
Element properties |
Spacer layout element
| Prop | Type | Description |
|---|---|---|
type |
'spacer' |
|
minLength |
number |
Minimum length |
Gauge layout element for circular progress
| Prop | Type | Description |
|---|---|---|
type |
'gauge' |
|
value |
string | number |
Current value key in data or direct value (0-1) |
style |
'automatic' | 'accessoryCircular' | 'accessoryCircularCapacity' | 'linearCapacity' |
Gauge style |
label |
string |
Label text |
currentValueLabel |
string |
Current value label |
minimumValueLabel |
string |
Minimum value label |
maximumValueLabel |
string |
Maximum value label |
tint |
ColorString |
Tint color |
properties |
BaseLayoutProperties |
Element properties |
Dynamic Island layout configuration
| Prop | Type | Description |
|---|---|---|
expanded |
DynamicIslandExpandedLayout |
Expanded state layout |
compactLeading |
LayoutElement |
Compact leading content |
compactTrailing |
LayoutElement |
Compact trailing content |
minimal |
LayoutElement |
Minimal presentation content |
Dynamic Island expanded layout configuration
| Prop | Type | Description |
|---|---|---|
leading |
LayoutElement |
Leading region content |
trailing |
LayoutElement |
Trailing region content |
center |
LayoutElement |
Center region content |
bottom |
LayoutElement |
Bottom region content |
Live Activity behavior configuration
| Prop | Type | Description |
|---|---|---|
widgetUrl |
string |
Widget URL for deep linking |
backgroundTint |
ColorString |
Background tint color |
systemActionForegroundColor |
ColorString |
System action foreground color |
keyLineTint |
ColorString |
Key line tint color |
Options for updating a Live Activity
| Prop | Type | Description |
|---|---|---|
activityId |
string |
Activity ID to update |
data |
Record<string, unknown> |
Updated data |
alertConfiguration |
ActivityAlertConfiguration |
Optional alert to show with update |
staleDate |
number |
Updated stale date |
relevanceScore |
number |
Updated relevance score |
Alert configuration for activity updates
| Prop | Type | Description |
|---|---|---|
title |
string |
Alert title |
body |
string |
Alert body |
sound |
string |
Sound name (optional) |
Options for ending a Live Activity
| Prop | Type | Description |
|---|---|---|
activityId |
string |
Activity ID to end |
data |
Record<string, unknown> |
Final data to display |
dismissalPolicy |
'default' | 'immediate' | 'after' |
Dismissal policy |
dismissAfter |
number |
Dismiss after timestamp (when dismissalPolicy is 'after') |
Result of getAllActivities
| Prop | Type | Description |
|---|---|---|
activities |
ActivityInfo[] |
List of activities |
Activity info returned from getAllActivities
| Prop | Type | Description |
|---|---|---|
activityId |
string |
Activity ID |
state |
'active' | 'ended' | 'dismissed' | 'stale' |
Current activity state |
startDate |
number |
Activity start date |
data |
Record<string, unknown> |
Current data |
Result of saving an image
| Prop | Type | Description |
|---|---|---|
success |
boolean |
Whether the save was successful |
imageName |
string |
Saved image name |
Options for saving an image
| Prop | Type | Description |
|---|---|---|
imageData |
string |
Base64 encoded image data |
name |
string |
Name to save the image as |
compressionQuality |
number |
JPEG compression quality (0-1, default 0.8) |
Result of removing an image
| Prop | Type | Description |
|---|---|---|
success |
boolean |
Whether the removal was successful |
Options for removing an image
| Prop | Type | Description |
|---|---|---|
name |
string |
Name of the image to remove |
Result of listing images
| Prop | Type | Description |
|---|---|---|
images |
string[] |
List of saved image names |
Result of starting a timer sequence
| Prop | Type | Description |
|---|---|---|
sequenceId |
string |
Unique sequence identifier |
Options for starting a timer sequence
| Prop | Type | Description |
|---|---|---|
steps |
TimerStep[] |
Array of steps in the sequence |
title |
string |
Overall title for the sequence (e.g., "HIIT Workout", "Tabata") |
loop |
boolean |
Whether to loop the sequence when complete |
loopCount |
number |
Number of times to loop (if loop is true, 0 means infinite) |
soundEnabled |
boolean |
Play sound on step change (default: true) |
vibrateEnabled |
boolean |
Vibrate on step change (default: true) |
countdownBeeps |
boolean |
Play countdown beeps in last 3 seconds (default: true) |
tapUrl |
string |
Deep link URL when tapping the notification/activity |
keepScreenOn |
boolean |
Keep screen on during timer (Android only, default: false) |
A single step in a timer sequence (e.g., workout interval)
| Prop | Type | Description |
|---|---|---|
duration |
number |
Duration of this step in seconds |
title |
string |
Title/instruction for this step (e.g., "Push-ups", "Rest") |
subtitle |
string |
Optional subtitle (e.g., "20 reps", "High intensity") |
color |
string |
Color for this step (hex color, e.g., "#FF0000" for work, "#00FF00" for rest) |
icon |
string |
Optional icon (SF Symbol name on iOS, material icon name on Android) |
sound |
'beep' | 'bell' | 'whistle' | 'countdown' | 'none' |
Optional sound to play when step starts |
Current state of a timer sequence
| Prop | Type | Description |
|---|---|---|
sequenceId |
string |
Sequence ID |
isRunning |
boolean |
Whether the sequence is running |
isPaused |
boolean |
Whether the sequence is paused |
isComplete |
boolean |
Whether the sequence is complete |
currentStepIndex |
number |
Current step index (0-based) |
totalSteps |
number |
Total number of steps |
currentStep |
TimerStep |
Current step info |
remainingSeconds |
number |
Remaining seconds in current step |
totalRemainingSeconds |
number |
Total remaining seconds for entire sequence |
elapsedSeconds |
number |
Total elapsed seconds |
currentLoop |
number |
Current loop iteration (1-based, if looping) |
totalLoops |
number |
Total loops (0 if infinite or not looping) |
Options for getting timer state
| Prop | Type | Description |
|---|---|---|
sequenceId |
string |
Sequence ID to get state for |
Event data for timer sequence events
| Prop | Type | Description |
|---|---|---|
type |
'stepChange' | 'complete' | 'tick' | 'paused' | 'resumed' | 'stopped' | 'loopComplete' |
Event type |
sequenceId |
string |
Sequence ID |
state |
TimerSequenceState |
Current state when event occurred |
Layout for the main activity view (lock screen widget)
Union type for all layout elements
LayoutElementContainer | LayoutElementText | LayoutElementImage | LayoutElementProgress | LayoutElementTimer | LayoutElementSpacer | LayoutElementGauge
Color string type - supports hex colors and system colors
string
Construct a type with a set of properties K of type T
{
[P in K]: T;
}
Callback type for timer sequence events
(event: TimerSequenceEvent): void
Inspired by ludufre/capacitor-live-activities with a simplified API and Capgo integration.