
Everyone building a website right now wants motion. When building our new capabilities deck website, we couldn't rise above the temptation.
In fact, when we wanted to add some complex animations to a recent project, we went straight for Lottie files... and then straight into a wall.
Lottie ships as a JSON file — a structured description of every shape, path, layer, and keyframe in the animation. Nothing is pre-rendered. When the page loads, a JavaScript player called Lottie-web parses that file and constructs the animation live, from data, in the browser.
Every shape becomes a real element injected into the page's document tree. A moderately complex animation can generate hundreds of these elements; a complex one can generate thousands. On every frame, up to sixty per second, the browser therefore recalculates each element's position, opacity, or path and updates the corresponding attributes.

All of this happens on the browser's main thread meaning scroll events, click responses, and every other JavaScript on the page may have to wait which can result in stutters, lag, and high memory usage.
Our first build consumed nearly 1.8GB of RAM after loading a few pages. All Lottie files combined were under 10MB.
The compounding is what catches people. Two complex animations on one page do not cost twice as much as one – they often cost four or five times as much, because their layout recalculations interfere with each other.
It’s worth knowing that there is now a binary .Lottie format, distinct from the .json, that compresses animation data by up to 80–90%. That said, it’s not as widely adopted and since our design tool of choice exported .json files, we had to compress the data through other means (more on this later.
An obvious alternative is to render the animation as video and use that instead. A compressed, muted, autoplaying MP4 is hardware-decoded, requires no JavaScript runtime, and is universally supported. But there are challenges.
In our case, the biggest problem is that autoplay is far less. When an iPhone is in Low Power Mode, Apple blocks video autoplay at the operating system level – not the browser level. There is no code workaround. The `play()` call does not throw an error; it never resolves. The user sees a frozen frame with no indication anything went wrong.
In fact, every major operating system now ships with system-level controls for visual animation. Windows 11 has "Animation effects" under Accessibility, Visual effects. macOS has "Reduce motion" under Accessibility, Display. These controls live above the browser.
For regular videos, play/pause controls resolve this that that’s not feasible on small animations or begin with a completely invisible state.
Needless to say, these settings do serve a role in helping individuals with motion sensitivity – we do not recommend trying to bypass accessibility guardrails, especially if your website or animation may have distressing effects (such as seizure-inducing lighting).
Given that this was for our experimental microsite, we decided that instead of ditching Lottie files completely, we are going to find a way to make them work.
After a lot of work, this is what helped us bring down the memory usage from nearly 2 gigabytes to roughly 300 megabytes:
Even after these changes, the difference wasn’t enough so we began looking outside the box (and the Lotties).
The single most counterintuitive thing we did was disable the browser's Back-Forward Cache – and it made the biggest difference.
The BF Cache (Back-Forward Cache) is a browser optimization that keeps entire pages – including their full JavaScript state – frozen in memory so that hitting the back or forward button feels instant. On a typical website this is a free performance win. On a site running multiple Lottie animations across multiple pages, it becomes a liability. Every page you navigate away from stays alive in memory, with its animation instances, DOM nodes, and all the overhead that comes with them intact.
Navigate across three or four pages and you are quietly accumulating the memory footprint of all of them simultaneously.
Opting out of BF Cache forces the browser to fully tear down each page on navigation, freeing the memory. The tradeoff is that back/forward navigation loses its instant feel.
For a presentation-style microsite where users are not expected to bounce between pages repeatedly, that tradeoff is worth making. For a content-heavy site where back navigation is part of the core flow, it probably is not.
You could argue this is cheating and that this doesn’t count as Lottie optimization. And you’d be 100% right.
The BF Cache call was as much a product decision as a technical one. We traded a UX convenience most users won't notice for a stability guarantee the site couldn't ship without.
For the kinds of complex, multi-layer animations we needed, Lottie was still the right format – not because the alternatives were worse in every dimension, but because nothing else gave us the same combination of designer control and reliable autoplay behavior. CSS cannot replicate illustration-level motion. Video fails in too many circumstances. Rive is powerful for interactive state-driven animation but requires a different workflow entirely and a steeper investment on both the design and development side.
That said, every one of those formats has advantages that Lottie doesn't. CSS costs almost nothing. Video is hardware-decoded. Rive runs a state machine that no linear sequence can match. The case for using them is real and gets stronger the simpler your animation requirement is.
What we’re getting at is…
Lottie files have an innate performance demand that no optimization in the world will completely negate.
Hence the choice: to Lottie or not to Lottie.