Install Motion Path — it’s free → See the product page
The short answer: three different things around a Figma Motion animation are called JSON, and they are not interchangeable. If you want a file that plays, you want Lottie JSON — Motion Path’s … → Copy as code → Lottie. If you want Figma’s own machine-readable description of the keyframes, you want Copy as → JSON in Figma itself. If you want to reproduce the setup that generated the motion, you want … → Config JSON.
Picking the wrong one is the most common mistake in this area, and it usually surfaces late — when a developer opens the file expecting an animation and finds a settings object, or opens a settings object expecting to play it. This page is here to prevent that.
This is what most people mean when they ask how to get JSON out of a Figma animation, even when they do not know the word Lottie. It is a complete, self-contained animation document: shapes, and the keyframes that move them, in a format iOS, Android, React Native and the web all consume at runtime.
Figma cannot produce it natively. Motion Path can:

The route is … → Copy as code → Lottie, then the copy or download icon in the panel header. Downloading saves motion-path.json with an application/json MIME type. Here is the whole sequence:

The document itself is small enough to read:
Everything that moves lives on ks, the layer transform. The shape inside is a placeholder sized to your object, so a developer swaps in real artwork — or parents their asset to that transform — and keeps the motion exactly.
The full walkthrough is Figma Motion export to Lottie; the getting-it-into-code side is Figma Motion export JSON.
This one is not in any plugin. It is Figma’s own handoff, and it works on a Motion Path animation for a specific reason worth understanding.
Motion Path does not run its own animation engine. It samples your path and writes native Figma Motion keyframe tracks onto the layer — position, rotation, scale, opacity, path trim. The tracks are Figma’s own, so everything Figma offers for its own animations works on the result. Dev Mode inspects them. Copy as emits CSS, React or JSON from them.
What you get is Figma’s representation of the keyframes on that layer. It is genuinely useful when a developer is already working in Dev Mode and wants Figma’s description rather than a third-party one, or when a tool in your pipeline consumes Figma’s shape. It is not a playable animation, and no Lottie player will read it.
There is also a practical consequence of this design that is easy to miss: because the keyframes are native, nothing about your file depends on the plugin remaining installed. Uninstall it and the animation is still there, still inspectable, still exportable through Figma’s own tools. The plugin is a way of authoring the tracks, not a runtime.
The third is in the same … menu as the exports, which is exactly why it gets confused with them.

Config JSON contains the settings that produced the motion — duration, direction, loops, easing, the effects you added, the speed profile — serialised into an object. It does not contain the animation. Nothing plays it. It exists so a technique can travel.
The round trip is the point. Copy the config, send it to a colleague, they paste it into the same box and press Apply pasted JSON. Their panel repopulates with your exact settings, and they pick their own path and go. It is a recipe, transmitted as text.

This is genuinely valuable for design-system work — a shared easing and speed profile that everyone applies to their own paths keeps motion consistent across a product in a way that sending finished animations never does. It is worthless as a handoff to engineering, because engineering cannot run it.
If you want to save a setup for yourself rather than send it, use Save as preset in the same menu instead; saving and reusing your own animations covers presets, and syncing presets to GitHub covers sharing them across a team properly.
The decision comes down to one question: what will the other end do with the file?
A useful sanity check before you send anything: open the file and look at the first few keys. A Lottie starts with "v", "fr", "ip", "op", "w", "h" and a "layers" array. A config does not. If you were expecting an animation and there is no layers key, you copied the wrong thing.
Open the position track and there will be far more keyframes than you placed on the canvas. People routinely read that as a bug, or as the export being wasteful, and it is neither.
Lottie has no equivalent of CSS’s offset-path. There is no way, in the format, to say “follow this curve with this easing” — so a curve cannot be two keyframes and a timing function. It has to be described point by point.
The easing then goes into when each of those points is reached rather than into a timing function, which is why the spacing is uneven. The result is better than a lossy conversion, not worse: your easing is preserved exactly rather than approximated by whichever cubic-bézier came closest. It is the same trade the plugin makes when baking to the Figma canvas, and the fidelity guide goes into it properly.
A file of a few hundred kilobytes is normal and compresses extremely well over the wire, because it is repetitive numeric text. It is still, in almost every case, smaller than the MP4 of the same animation — and unlike the MP4 it is resolution-free.
The rule is simple enough to hold in your head: anything riding the layer transform is in the JSON, and anything living in the artwork or on the canvas is not. Position, rotation, scale, opacity and the timing that drives them all cross over. Colour shift, motion blur, motion trail, squash & stretch and anticipation do not, because they key the fill, add ghost copies, or extend the motion past the path ends — none of which is a transform.
The plugin prints these as notes under the snippet rather than dropping them silently, which is the behaviour you want. An effect that quietly vanished is discovered on a device weeks later; an effect named at export time is a decision you make now.
All three describe motion. None of them describe the interface the motion happens in, and this trips up teams who reach for a JSON export expecting a complete handoff.
No component variants. No auto-layout rules. No text styles or colour tokens. No prototype interactions outside the timeline. A Lottie carries a placeholder shape rather than your artwork, deliberately — and even Figma’s own JSON describes keyframes on a layer, not the design system the layer belongs to.
If what you actually need handed over is the interface, none of this is the tool; Dev Mode is. These exports are for the movement.
The export writes Lottie schema version 5.9.0, which is the version every current player consumes without a shim. That choice is conservative on purpose. Lottie’s newer features are unevenly implemented across the four official players, and a document that renders beautifully in lottie-web and subtly wrongly on Android is worse than one that renders identically everywhere.
Because the animation rides the layer transform and nothing more exotic, it sits well inside what 5.x guarantees. That is a large part of why the placeholder-shape design exists: keeping the moving parts to position, rotation, scale and opacity keeps the file inside the intersection of what every player agrees on, rather than the union of what each supports individually.
The practical implication for you is that you should not need to ask a developer which Lottie version their player is on. If they are on a maintained release of any of the four, it will read the file.
Assuming you wanted the playable one, this is the shape of the integration on each platform:
Short on every platform, and the file is the same in each case — which is most of the argument for Lottie over per-platform animation code.
One caveat to pass on with the file: looping is a player setting, not a property of the JSON. The document holds one clean pass of the motion. If your Figma animation repeated the traversal, the export notes will say so.
For a JSON that plays: apply the motion, then … → Copy as code → Lottie in Motion Path, and copy or download it. For Figma’s own description of the keyframes, use Figma’s native Copy as → JSON. For the plugin settings, use … → Config JSON.
Lottie is a specific JSON schema for vector animation — so every Lottie file is JSON, but very little JSON is Lottie. A Lottie document begins with keys like v, fr, ip, op and a layers array. If those are missing, a Lottie player will not read it.
Figma’s Copy as → JSON gives you Figma’s representation of the Motion keyframes, which is real and useful but is not a playable animation document. For Lottie you need a plugin, because Figma does not emit that format.
Moving a setup between files or people. It holds the plugin settings that generated the motion — duration, direction, loops, easing, effects — so someone can paste it, press Apply pasted JSON, and rebuild the same recipe on their own path. It is not an animation and nothing plays it.
Lottie, in nearly every case — it is the one they can ship. Send an MP4 alongside it so they can see the intended result without opening a player.
motion-path.json, saved by your browser with an application/json MIME type, in whatever download location your browser uses. The copy button puts identical content on the clipboard.
No. The Lottie carries a placeholder shape sized to your object, because the motion lives on the transform rather than in the shape. A developer replaces the placeholder, or parents real artwork to its transform, and the motion is untouched.
No. The plugin writes native Figma Motion keyframes, so the animation belongs to your file rather than to the plugin. You would lose the ability to author new paths, not the work already applied.
You can, but it is usually a mistake on a file that will be re-exported: a hand-edited Lottie cannot be regenerated without losing the edit, which quietly makes the Figma file stop being the source of truth. Change it in Figma and export again instead.
Install Motion Path — it’s free → Browse 300+ animation examples