Live Activity, Dynamic Island & Widget Animation Limits
By the Charmotion team · Updated

Live Activities, the Dynamic Island and widgets cannot play a continuous looping animation. Since iOS 17 they animate data changes with SwiftUI transitions and animations, each capped at two seconds, and nothing animates on Always-On displays. For a character, swap static poses with a transition when the data changes instead of playing Rive, Lottie, GIF or video.
Key takeaways
- Apple's WidgetKit docs: "Animations in widgets and Live Activities have a maximum duration of two seconds."
- An Apple DTS engineer said continuous Dynamic Island and widget animations are not supported and called the timer-font trick an unsupported hack.
- Use
transition(_:),contentTransition(_:),animation(_:value:)andid(_:);Transactionis unavailable. - Live Activity data is limited to 4 KB, and an activity can stay active for up to eight hours.
- Export still poses from your animation set and ship them as images in the widget extension.
Can a Live Activity or Dynamic Island play a looping character animation?
No. Widgets and Live Activities are rendered by the system from your SwiftUI view hierarchy at update time; your code does not run a render loop on the Lock Screen or in the Dynamic Island. Animations happen only as a transition from one rendered state to the next.
Developers regularly ask about this on Apple's forums. In one thread about animating the Dynamic Island and widgets, an Apple DTS engineer answered that "there is a hack some developers have figured out but it is not supported by the system and cannot be recommended," and that the kind of continuous animation shown "is not supported and can cause battery drain." The hack in question abuses timer text with custom fonts to fake frames; it can break in any release.
So a mascot cannot idle, breathe or blink in a Live Activity. It can change pose, with a short animated transition, whenever your app or a push notification updates the activity.

What animations do widgets and Live Activities support?
Apple's article "Animating data updates in widgets and Live Activities" lists what works. Since iOS 17, widgets and Live Activities "support all built-in SwiftUI transitions and animations." In earlier OS versions, widgets don't animate, and Live Activities on iOS 16 or earlier ignore animation modifiers and use system timing, though built-in transitions still apply.
| Supported | Not supported |
|---|---|
| Default content transitions on text, images and SF Symbols | Continuous or repeating animations |
transition(_:): opacity, move(edge:), slide, push(from:) and combinations | Transaction (so you can't cancel animations with it) |
contentTransition(_:), including .numericText(countsDown:) | Animations longer than two seconds |
animation(_:value:) and springs | Any animation in Always-On low-luminance mode |
id(_:) to animate a view when related data changes | Running your own render loop or timers |
To turn off animation for a view, Apple says to pass .identity to transition(_:) or nil to animation(_:value:).
What is the 2-second animation limit?
Both the WidgetKit documentation and the Live Activities section of the Human Interface Guidelines state the same cap: animations in widgets and Live Activities have a maximum duration of two seconds, whether they are system or custom animations.
In practice, design every transition to finish well inside that window. A spring with a long settle time may be cut off; a .smooth(duration: 0.6) or .spring(duration: 0.5, bounce: 0.3) stays comfortably within it. If an update changes several views, Apple suggests disabling animation on the less important ones so attention goes to the main change.
struct ScoreView: View {
let score: Int
var body: some View {
Text(score, format: .number)
.font(.title.monospacedDigit())
.contentTransition(.numericText())
.animation(.spring(duration: 0.5, bounce: 0.3), value: score)
}
}Can I play GIF, Lottie, Rive or video in a widget?
Not as playback. The supported mechanism is SwiftUI's own transitions and animations, rendered by the system; there is no hook for a player that advances frames over time. Rive and Lottie both need a live render loop, and a widget or Live Activity does not provide one. GIF and video playback are likewise not part of the documented animation model, and DTS has called continuous animation unsupported.
What you can do with those assets is use a frame from them. Export a still for each mood from your character's videos and bundle the images in the widget extension's asset catalog. With ffmpeg, a frame from a transparent WebM keeps its alpha if you decode with libvpx:
ffmpeg -c:v libvpx-vp9 -i happy.webm -ss 1.0 -frames:v 1 mascot-happy.png
ffmpeg -c:v libvpx-vp9 -i loading.webm -ss 1.0 -frames:v 1 mascot-loading.png
Charmotion sets include transparent WebM and MOV versions of all 17 animations, so every mood and reaction is available as a source for these stills. Resize them to the point sizes you actually display; the Live Activity minimal presentation, for example, should not exceed 45×36.67 points.
What are the 4 KB data and eight-hour limits?
From Apple's ActivityKit documentation, "Displaying live data with Live Activities":
| Limit | Value |
|---|---|
| Static and dynamic data per update (including push payloads) | 4 KB combined |
| Active lifetime | Up to eight hours |
| Total time on the Lock Screen | Up to 12 hours (eight active plus up to four after it ends) |
| Minimal presentation image | No larger than 45×36.67 points |
| Animation duration | Two seconds maximum |
The 4 KB limit is why images never travel in the payload. Send a small value, such as a mood index, and look up a bundled image:
import ActivityKit
struct DeliveryAttributes: ActivityAttributes {
struct ContentState: Codable, Hashable {
var mood: Int // 0 idle, 5 loading, 1 happy ...
var minutesLeft: Int
}
var orderNumber: String
}
The HIG adds that Live Activities suit tasks that do not exceed eight hours and that, after an activity ends, 15 to 30 minutes on the Lock Screen is adequate in most cases.
What happens on an Always-On display?
On devices with an Always-On display, Apple says "the system doesn't perform animations to preserve battery life in Always On." Check the isLuminanceReduced environment value (iOS 16 and later) and adapt: skip the transition and show a simpler, darker pose.
struct MascotPose: View {
@Environment(\.isLuminanceReduced) private var isLuminanceReduced
let mood: Int
var body: some View {
Image("mascot-mood-\(mood)")
.resizable()
.scaledToFit()
.opacity(isLuminanceReduced ? 0.6 : 1)
.id(mood)
.transition(isLuminanceReduced ? .identity : .push(from: .bottom))
}
}
Keep low-luminance artwork simple: large bright areas look harsh on a dimmed Lock Screen.
What is the best alternative to a looping mascot in a Live Activity?
Pose swaps. Treat each mood as a still image, and let the system animate between them when the state changes. Apple's documented pattern for animating a view when other data changes is to associate the view with that data through id(_:) and add a transition; here the mood is the identity:
import SwiftUI
import WidgetKit
struct DeliveryLockScreenView: View {
let state: DeliveryAttributes.ContentState
var body: some View {
HStack(spacing: 12) {
MascotPose(mood: state.mood)
.frame(width: 56, height: 56)
.accessibilityHidden(true)
VStack(alignment: .leading) {
Text("Arriving in")
.font(.caption)
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(state.minutesLeft, format: .number)
.contentTransition(.numericText(countsDown: true))
Text("min")
}
.font(.title2.bold())
}
}
.padding()
}
}
Each update then produces one short, meaningful motion: the character pushes in with a new pose while the minutes tick down. Map moods to the activity's phases (preparing → loading pose, on the way → happy, delayed → sad, delivered → a success pose) and you get a character that feels alive without breaking the platform's rules. In the full app, use the real animated character; the full-motion version belongs there.

Frequently asked questions
Can I animate the Dynamic Island with a timer-font trick?
It has been done, but an Apple DTS engineer said the approach is not supported by the system, cannot be recommended, and that continuous animations can drain battery. It can break in any iOS update. Use supported transitions between data updates instead.
Do widgets animate on iOS 16?
No. Apple's documentation says that in OS versions before iOS 17, widgets don't animate. Live Activities on iOS 16 ignore animation modifiers such as animation(_:value:) and use system timing, but built-in transitions like opacity, move, slide and push still apply.
Can I send a mascot image in a Live Activity push?
Not practically. All static and dynamic Live Activity data, including push payloads, must fit in 4 KB combined. Bundle the pose images in the widget extension and send only a small value, such as a mood number, that selects which image to show.
How long can a widget or Live Activity animation last?
Two seconds at most. Apple's WidgetKit documentation and the Live Activities Human Interface Guidelines both state that system and custom animations in widgets and Live Activities have a maximum duration of two seconds. Keep springs and transitions comfortably shorter so they are not cut off mid-motion.
Quick answers from this guide
Sources
- Animating data updates in widgets and Live Activities — Apple
- Displaying live data with Live Activities — Apple
- Human Interface Guidelines: Live Activities — Apple
- How to use animation for Dynamic Island and widgets? — Apple Developer Forums
- numericText(countsDown:) — Apple
- isLuminanceReduced — Apple