Lottie — an open-source library from Airbnb that renders vector animation exported from Adobe After Effects into JSON format via the Bodymovin plugin. Animations are rendered programmatically without quality loss at any screen resolution. According to GitHub (2026), Lottie is used in over 50,000 projects on iOS, Android, and Web. Learn more about other types of animation in the general guide to animation.
Key Takeaways
Lottie — a cross-platform library for playing vector animation, developed at Airbnb in 2015. It solves the problem of heavy video files and raster sprite sheets: a designer creates animation in After Effects, exports it via Bodymovin to JSON, and a developer embeds this file into a mobile app. Lottie renders animation programmatically via Canvas, Core Animation, or Skia, depending on the platform.
The main advantage of Lottie — vector animation scales without quality loss on any screen: from Apple Watch to 4K TVs. The animation JSON file size is typically 5–50 KB, which is tens of times smaller than the equivalent video file. According to Airbnb Engineering (2025), Lottie supports over 80% of Adobe After Effects features, including masks, effects, curves, and expressions.
Bodymovin — is a plugin for After Effects (free, GitHub) that serializes a composition into JSON format understood by the Lottie runtime. Supports After Effects CC 2018 and newer. For complex animations with many keyframes, dotLottie is recommended — a format based on Lottie JSON but compressed and packaged into a single file.
Lottie uses a layered rendering architecture that adapts to platform capabilities. On Android, animation is drawn via the Canvas API — Lottie's own renderer (LottieDrawable), which does not use system animations. On iOS, Lottie relies on Core Animation Layers, providing high performance and 60 FPS. On Flutter, Lottie uses Skia Canvas via CustomPainter.
Rendering goes through three stages: JSON parsing — parsing the animation into LottieComposition (all layers, shapes, keyframes); interpolation — computing intermediate values between keyframes considering easing curves; drawing — rendering the current frame on Canvas or via Core Animation. Lottie supports hardware acceleration: on Android — acceleration via Canvas with Hardware Accelerator, on iOS — CALayer with built-in GPU acceleration of Core Animation.
| Platform | Renderer | Hardware Acceleration | Library |
|---|---|---|---|
| Android | Canvas (LottieDrawable) | Hardware Accelerator (API 14+) | com.airbnb.lottie |
| iOS | Core Animation (CALayer) | GPU (Metal, OpenGL) | Lottie-iOS |
| Flutter | Skia Canvas (CustomPainter) | Impeller (Flutter 3.16+) | lottie_flutter |
| React Native | Native bridge | Depends on platform | lottie-react-native |
On Android, LottieAnimationView extends AppCompatImageView and handles the entire loading and rendering cycle. The JSON file is placed in the res/raw or assets folder. LottieAnimationView supports playback control — play, pause, resume, setFrame, setProgress, repeat, speed — and listening via AnimatorUpdateListener and AnimatorListener.
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animationView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:lottie_rawRes="@raw/loading_animation"
app:lottie_autoPlay="true"
app:lottie_loop="true" />
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieListener
// Programmatic setup of LottieAnimationView
val lottieView = LottieAnimationView(context).apply {
setAnimation(R.raw.celebrate_animation)
repeatCount = ValueAnimator.INFINITE
speed = 1.5f
addAnimatorUpdateListener { animator ->
val progress = animator.animatedValue as Float
progressBar.progress = (progress * 100).toInt()
}
playAnimation()
}
// Loading from assets and caching
lottieView.setAnimation("animations/confetti.json")
lottieView.setCacheStrategy(LottieAnimationView.CacheStrategy.Strong)
// LottieDrawable — custom drawing without View
val drawable = LottieDrawable().apply {
setComposition(
LottieCompositionFactory.fromRawRes(context, R.raw.star)
.addListener { composition -> composition?.let { setComposition(it); play() } }
)
}
Android best practices: use setCacheStrategy(CacheStrategy.Strong) for frequently repeating animations — the composition is cached in memory, and each new instance does not parse JSON again. For lists (RecyclerView), use LottieAnimationView with enableMergePathsForKitKatAndAbove(true) and disableExtraScaleModeForOlderWorkarounds() to optimize rendering. For animations with a transparent background, set android:layerType="hardware" for GPU acceleration.
On iOS, AnimationView is the main Lottie class for UIKit and SwiftUI. It is added via Swift Package Manager or CocoaPods. JSON files are added to the project bundle. AnimationView automatically determines the scale (logical screen density) and uses Core Animation to render layers at 60 FPS.
import Lottie
// UIKit: AnimationView with manual control
let animationView = AnimationView(name: "confetti")
animationView.frame = view.bounds
animationView.contentMode = .scaleAspectFit
animationView.loopMode = .loop
animationView.animationSpeed = 1.5
animationView.play(fromProgress: 0, toProgress: 0.5) { finished in
print("Animation segment finished: \(finished)")
}
view.addSubview(animationView)
// UIKit: animation with progress (for binding to events)
animationView.play(fromFrame: AnimationFrameTime(30),
toFrame: AnimationFrameTime(90))
// SwiftUI: LottieView as UIViewRepresentable
import Lottie
import SwiftUI
struct LottieView: UIViewRepresentable {
let name: String
var loopMode: LottieLoopMode = .loop
@Binding var progress: CGFloat
func makeUIView(context: Context) -> AnimationView {
let view = AnimationView(name: name)
view.contentMode = .scaleAspectFit
view.loopMode = loopMode
return view
}
func updateUIView(_ uiView: AnimationView, context: Context) {
uiView.currentProgress = progress
}
}
// Using in SwiftUI
LottieView(name: "loading", progress: $animationProgress)
.frame(width: 100, height: 100)
iOS best practices: for animations that start immediately after loading, use animationView.play(fromProgress: 0, toProgress: 1) with loopMode = .playOnce for one-time accent effects. For Lottie in UITableView/UICollectionView, use AnimationView with a cached animation file via LottieAnimation.cached. Rendering a large number of layers (50+) may cause FPS drops — in such cases, enable renderingEngine = .mainThread (default) or .coreAnimation for macOS.
Lottie fundamentally differs from video files: it does not store pixels, but describes vector shapes, their transformations, and curves of change over time. Video (MP4, WebM) is a sequence of raster frames at a fixed resolution. The difference manifests in file size, scaling quality, interactivity, and performance.
| Parameter | Lottie (JSON) | Video (MP4) | GIF |
|---|---|---|---|
| File size | 5–50 KB | 200–2000 KB | 500–5000 KB |
| Scaling quality | Vector (infinite) | Fixed (pixel) | Fixed |
| Interactivity | Progress, speed, pause, color change | No | No |
| Alpha channel (transparency) | Native | Requires codec | Supported |
| Performance (CPU) | Low load | Medium (decoding) | High (raster decoding) |
When to choose Lottie: loading icons, likes/reaction animations, onboarding screens, accent micro-animations of buttons. For complex scenes with 3D effects, realistic lighting, or photorealistic characters, video remains a more practical choice. Lottie is not designed for playing long scenes (more than 10 seconds) — the optimal duration of one animation is 2–5 seconds.
Lottie performance depends on the number of layers, complexity of masks and effects, and the renderer. To maintain 60 FPS on mid-range devices, follow these recommendations: limit the number of layers to 30–40 per scene, avoid overlapping nested pre-compositions, use dotLottie for complex animations.
// Optimizing Lottie for RecyclerView
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieDrawable
import com.airbnb.lottie.LottieCompositionFactory
// Caching composition in memory
private val cache = LottieCompositionFactory.setCacheStrategy(CacheStrategy.Strong)
// LottieAnimationView pool for reuse
class LottiePool {
private val pool = LinkedList<LottieAnimationView>()
fun acquire(context: Context): LottieAnimationView {
return pool.poll() ?: LottieAnimationView(context)
}
fun release(view: LottieAnimationView) {
view.pauseAnimation()
view.cancelAnimation()
pool.add(view)
}
}
// Disabling unnecessary features
lottieView.enableMergePathsForKitKatAndAbove(true)
lottieView.setHardwareAcceleration(true)
lottieView.setMaxFrame(60) // Limiting frame count
Additional optimizations: enable enableMergePathsForKitKatAndAbove(true) for devices with Android 4.4+ — this merges overlapping paths into a single path, reducing the number of draw calls. Use dotLottie instead of JSON — the binary format compresses animation by 50–80% through protobuf serialization, reducing parsing time. For animations in RecyclerView, set repeatCount = 0 (single play) and stop animation on scroll via recyclerView.addOnScrollListener. According to Airbnb Engineering Blog (2025), these measures reduce CPU load by up to 40%.
Frequently Asked Questions
Use dotLottie — a binary format based on protobuf that compresses JSON by 50–80%. In After Effects, export via Bodymovin with the "Glyphs" setting = None (if text is not needed), disable unnecessary guides and guide layers. Remove invisible layers and layers with 0% opacity before export.
Check the minimum SDK version: Lottie for Android supports API 14+, but some effects (Path Morphing, Gradient) only work on API 21+. On iOS, Lottie requires iOS 11+. For old devices, use a fallback — a static png frame from the animation. Load animations asynchronously via LottieCompositionFactory with error handling via LottieListener.onFailure.
Yes, via LottieDynamicProperties or KeyPath. Set the Layer Name in After Effects (e.g., "icon-fill"), then in code: lottieView.addValueCallback(KeyPath("icon-fill"), LottieProperty.COLOR) { Color.GREEN }. This allows customizing the animation to the app theme without creating duplicate files. For iOS, use AnimationView.setValueProvider(ColorValueProvider).
Lottie — a format for playing pre-created animation from After Effects. Rive — interactive animation with State Machine, triggers, and inputs. Lottie is suitable for passive animations (loading, likes, welcome screens). Rive is for games, interactive UI elements, animations with feedback on user actions. Rive requires its own editor, Lottie works through the familiar After Effects.
On Android: lottieView.addAnimatorListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { ... } }). On iOS: animationView.play { finished in }. In SwiftUI: use Binding for currentProgress with onChange. For Kotlin Multiplatform, use LottieAnimatable from the lottie-compose library.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also