Best practices for shipping Lottie
Most Lottie performance problems are introduced at export time, not runtime. Once a designer delivers a 70 MB JSON, the only options downstream are compression or replacement. This article collects concrete rules of thumb for each role involved — designer, developer, product — so the bad export doesn't happen in the first place.
For designers
Prefer vector layers over rasterized effects
Any effect that can be expressed with shape layers, vector masks, gradient fills, or AE's built-in path operations will export as compact Lottie data. The moment you reach for the Particle Systems 2 plugin, Trapcode Form, or a video sub-comp, you've crossed into raster territory and Bodymovin will rasterize the affected frames as PNG sequences. Sometimes this is unavoidable — a beautiful smoke trail isn't going to come out of bezier paths — but it should be a conscious choice, not an accidental one.
Avoid time-remapping on non-vector layers
Time remapping on a layer that already requires rasterization compounds the frame-sequence problem: Bodymovin has to render every frame of the remapped range to PNG. A 2-second clip at 60 fps with 2× time remapping renders 240 frames where 120 would have sufficed. Bake the time effect into the source if you can.
Keep your composition size honest
Bodymovin renders embedded image frames at the composition resolution. A 2160 × 2160 comp rendering raster frames at 30 fps is producing 4× the byte count of a 1080 × 1080 comp, even if the final UI never displays it larger than 200 × 200. Size your composition for the target display resolution. If the animation will be rendered at a maximum of 400 pixels wide on screen, your comp can be 800 × 800 (2× for retina) — no larger.
Render a test export before handing off
Bodymovin's "Render" panel shows you the output file size before saving. If it reads above 10 MB, that's a sign you should either rework the effect with vector primitives or commit to a video export instead. Don't deliver an unviewable file to the engineer and expect them to rescue it post hoc.
Use dotLottie when the effect requires raster
If you must ship with embedded images, the .lottie format is meaningfully smaller than equivalent inline JSON because the PNGs are stored as binary entries rather than base64. Recent Bodymovin and LottieFiles tooling both produce .lottie directly.
For developers
Run every incoming Lottie through the Inspector
Before integrating a designer's animation, drop the file into the Inspector tool. The byte breakdown tells you in two seconds whether you have a problem. If embedded raster is over 20% of the file or total size is over 1 MB, push back or compress before integration.
Lazy-load Lottie players
The lottie-web player itself is 250–350 KB minified depending on which build you import. On bundles where Lottie is used in one optional flow (e.g. an onboarding screen), dynamic import("lottie-web") on demand keeps it out of your first-paint payload.
Use canvas renderer for image-heavy animations
lottie-web supports SVG, Canvas, and HTML renderers. SVG is the default and handles vector animations beautifully, but performs poorly with embedded raster sequences because every frame creates and tears down DOM elements. For image-sequence-heavy Lottie, the canvas renderer is typically 3–5× more efficient.
Don't autoplay everywhere
Lottie animations sustained for hours (typical of loading spinners or background ambience) can keep a tab at 5–15% CPU even when not visible. Use IntersectionObserverto pause animations that scroll off-screen, and pause on tab visibility change with the Page Visibility API.
Cache aggressively
Lottie files are content-addressable: once a particular animation is in production, it doesn't change. Serve them with a long Cache-Control: public, max-age=31536000, immutableheader and include a content hash in the filename. Many sites lose 60–80% of their potential Lottie load time to a missing immutable cache.
For product managers and PMs
Set a hard size budget per animation
Without a budget, animations creep upward over time. A reasonable default ceiling is 200 KB for any single animation on the critical render path, and 1 MB for animations on secondary flows. Anything larger needs explicit approval and a compression pass.
Decide Lottie vs video early
Lottie's strengths are: interactivity (event hooks, color theming, parameter binding), small size for vector content, sharpness at any DPI, and easy programmatic control. Its weakness is anything photographic or particle-heavy, where video formats win by 5–10× on byte cost.
If the animation is fixed (no interactivity required) and has heavy raster content, a 5-second MP4 at the right resolution will typically be smaller than even an aggressively compressed Lottie equivalent. Don't ship Lottie out of habit when video is the better tool.
Measure adoption, not just shipping
Track Lottie load times and player initialization errors in your real user monitoring. A heavy Lottie file in a slow-3G scenario can delay the meaningful-paint metric significantly, but the issue won't show up in synthetic CI because synthetic networks are fast. Real user monitoring is the only signal that tells you whether your animation strategy is working.
A quick decision flowchart
- Is the content purely vector (shapes, paths, gradients)? → ship Lottie.
- Is the content mostly vector with one or two small raster accents? → ship Lottie, but compress.
- Is the content image-heavy but interactive (theming, event-driven, parameter-bound)? → ship Lottie, compress aggressively.
- Is the content image-heavy and non-interactive? → ship MP4 or WebM.
- Is the content over 30 seconds? → almost always video.
Tools referenced in this article
- Lottie Inspector — file-size breakdown and JSON editor
- Lottie Compressor — in-browser WebP re-encoding and frame skipping
- Lottie Preview — side-by-side comparison playback