Managing Live Activities locally
Live Activities are dynamic interfaces that display real-time information on iOS devices. Voltra provides a comprehensive set of APIs for managing the complete lifecycle of Live Activities directly from your React Native app, without requiring server-side infrastructure.
Voltra offers both imperative APIs for direct control and React hooks for seamless integration with your components.
This page documents the legacy server-rendered engine. For the separate engine that bundles a definition with the app and updates it with props, see Dynamic Live Activities.
Imperative APIs
Section titled “Imperative APIs”The imperative APIs provide direct, programmatic control over Live Activities. These are the core functions you’ll use to manage Live Activity lifecycles. For the shape of the variants object used below, see Supported variants.
Starting Live Activities
Section titled “Starting Live Activities”Use startLiveActivity() to create and display a new Live Activity.
import { Voltra } from '@use-voltra/ios'import { startLiveActivity } from '@use-voltra/ios-client'
const variants = { lockScreen: ( <Voltra.VStack style={{ padding: 16, borderRadius: 18, backgroundColor: '#101828' }}> <Voltra.Text style={{ color: '#F8FAFC', fontSize: 18, fontWeight: '600' }}> Order Confirmed </Voltra.Text> <Voltra.Text style={{ color: '#94A3B8', fontSize: 12, marginTop: 8 }}> Your order is being prepared </Voltra.Text> </Voltra.VStack> ), // Define compact, minimal, and expanded variants for Dynamic Island compact: <Voltra.Text>Order confirmed</Voltra.Text>, minimal: <Voltra.Symbol name="checkmark.circle.fill" tintColor="#10B981" />, expanded: ( <Voltra.VStack style={{ padding: 16 }}> <Voltra.Text style={{ fontSize: 16, fontWeight: '600' }}>Order Confirmed</Voltra.Text> <Voltra.Text style={{ fontSize: 12, color: '#6B7280', marginTop: 4 }}> Your order is being prepared </Voltra.Text> </Voltra.VStack> ),}
const activityId = await startLiveActivity(variants, { activityName: 'order-123', // Optional: for re-binding on app restart deepLinkUrl: 'myapp://order/123', // Optional: URL to open when tapped channelId: 'CTrNsYq/Ee8AALLzHQaVlA==', // Optional: broadcast channel (iOS 18+) dismissalPolicy: { after: 30 }, staleDate: Date.now() + 60 * 60 * 1000, // 1 hour relevanceScore: 0.8,})Parameters:
variants: ALiveActivityVariantsobject defining the UI for different display contextsoptions: Configuration options (see Configuration Options section below)
Returns: A promise that resolves to the Live Activity ID (string)
Updating Live Activities
Section titled “Updating Live Activities”Use updateLiveActivity() to modify the content and configuration of an active Live Activity.
import { Voltra } from '@use-voltra/ios'import { updateLiveActivity } from '@use-voltra/ios-client'
const updatedVariants = { lockScreen: ( <Voltra.VStack style={{ padding: 16, borderRadius: 18, backgroundColor: '#101828' }}> <Voltra.Text style={{ color: '#F8FAFC', fontSize: 18, fontWeight: '600' }}> Order Ready </Voltra.Text> <Voltra.Text style={{ color: '#94A3B8', fontSize: 12, marginTop: 8 }}> Your order is ready for pickup </Voltra.Text> <Voltra.Button onPress="pickup-order" style={{ marginTop: 12 }}> I'm Here </Voltra.Button> </Voltra.VStack> ), compact: <Voltra.Text>Ready for pickup</Voltra.Text>, minimal: <Voltra.Symbol name="bag.fill" tintColor="#F59E0B" />,}
await updateLiveActivity(activityId, updatedVariants, { dismissalPolicy: { after: 300 }, // 5 minutes relevanceScore: 1.0, // High priority now})Parameters:
activityId: The ID returned fromstartLiveActivity()variants: Updated UI variantsoptions: Updated configuration options
Stopping Live Activities
Section titled “Stopping Live Activities”Use stopLiveActivity() to end a Live Activity.
import { stopLiveActivity } from '@use-voltra/ios-client'
await stopLiveActivity(activityId, { dismissalPolicy: { after: 10 }, // Keep visible for 10 seconds after ending})Parameters:
activityId: The ID of the Live Activity to stopoptions: Final configuration options
Checking Live Activity status
Section titled “Checking Live Activity status”Use isLiveActivityActive() to check if a specific Live Activity is currently active.
import { isLiveActivityActive } from '@use-voltra/ios-client'
if (isLiveActivityActive('order-123')) { console.log('Live Activity is active')} else { console.log('Live Activity is not active')}Parameters:
activityName: The name of the Live Activity to check (same asactivityNameused when starting the activity)
Returns: Boolean indicating whether the Live Activity is currently active
Utility functions
Section titled “Utility functions”Platform detection
Section titled “Platform detection”import { isGlassSupported } from '@use-voltra/ios-client'
function App() { // Check if the device supports Liquid Glass (iOS 26+) if (isGlassSupported()) { // Use Liquid Glass features }}Voltra also exposes useIsHeadless() for detecting when your app was launched in the background (e.g. to handle a push token refresh without mounting your UI). See Handling background execution for the full explanation and example.
Ending all Live Activities
Section titled “Ending all Live Activities”Use endAllLiveActivities() to immediately end all active Live Activities in your app.
import { endAllLiveActivities } from '@use-voltra/ios-client'
// End all Live Activities (useful for cleanup or logout scenarios)await endAllLiveActivities()Note: This function ends all Live Activities immediately without applying any dismissal policies. Use this for bulk cleanup scenarios rather than individual activity management.
Development tools
Section titled “Development tools”For development-friendly APIs that provide automatic updates and easier testing, see the Development documentation.
Event handling
Section titled “Event handling”Live Activities emit events that you can listen to for state changes and user interactions. See the Events API documentation for detailed information on subscribing to and handling Live Activity events.
Configuration options
Section titled “Configuration options”Voltra provides several configuration options to control Live Activity behavior, lifecycle, and appearance. These options can be used with startLiveActivity(), updateLiveActivity(), and stopLiveActivity().
Dismissal policy
Section titled “Dismissal policy”Controls how Live Activities behave after they end.
Options:
'immediate'(default): Live Activity is dismissed immediately when it ends{ after: number }: Live Activity remains visible for the specified number of seconds after ending, then automatically dismisses
Examples:
// Immediate dismissal (default)await startLiveActivity(variants, { dismissalPolicy: 'immediate',})
// Keep visible for 30 seconds after endingawait startLiveActivity(variants, { dismissalPolicy: { after: 30 },})
// Update dismissal timing for active Live Activitiesawait updateLiveActivity(activityId, variants, { dismissalPolicy: { after: 300 }, // 5 minutes})
// Set dismissal timing when stoppingawait stopLiveActivity(activityId, { dismissalPolicy: { after: 10 },})The dismissal policy applies to both programmatic ending and natural ending (when timers expire).
Stale date
Section titled “Stale date”Specifies when a Live Activity should be considered stale and automatically dismissed by iOS.
// Dismiss after 1 hourawait startLiveActivity(variants, { staleDate: Date.now() + 60 * 60 * 1000,})
// Dismiss after 2 hoursawait startLiveActivity(variants, { staleDate: Date.now() + 2 * 60 * 60 * 1000,})Note: If you provide a staleDate in the past, it will be ignored.
Relevance score
Section titled “Relevance score”Helps iOS prioritize which Live Activities to display when space is limited.
Range: 0.0 to 1.0 (default: 0.0)
// High priority (e.g., active delivery)await startLiveActivity(variants, { relevanceScore: 0.8,})
// Low priority (e.g., background task)await startLiveActivity(variants, { relevanceScore: 0.2,})Live Activities can receive updates even when your app is in the background or terminated, but they cannot execute JavaScript code. For real-time updates from backgrounded apps, use server-side push notifications.
Channel ID (broadcast push, iOS 18+)
Section titled “Channel ID (broadcast push, iOS 18+)”Subscribes the Live Activity to a broadcast channel for server-side updates. When provided, the activity receives updates via broadcast push notifications instead of individual device tokens—one server notification updates all activities on that channel.
// For shared content (e.g., live sports, flight status)await startLiveActivity(variants, { activityName: 'match-123', channelId: 'CTrNsYq/Ee8AALLzHQaVlA==', // From APNs channel management})Requires enablePushNotifications: true in the Voltra plugin and the Broadcast Capability enabled in your Apple Developer account. See Server-side updates for details.
Best practices
Section titled “Best practices”- Provide an
activityNamewhen starting a Live Activity, so you can re-bind to it (e.g. viaisLiveActivityActive) after an app restart. - Set a
staleDateso iOS can automatically dismiss activities you forget to end (e.g. after a delivery is likely already complete). - Provide a
deepLinkUrlso tapping the Live Activity takes users somewhere useful in your app. - Pick a
dismissalPolicydeliberately —{ after: N }is useful when you want users to see a final state (like “Delivered”) before it disappears.