In this article
There is a tool on GitHub called lottielab-watermark-remover. It is a few lines long. All it does is walk the layers array of a Lottie file and delete the one whose index is 12345679. That single hardcoded number tells you everything about how these watermarks work.
What a Lottie file actually is
Strip a Lottie down and it is one JSON object with about eight keys that matter. fr is the frame rate. ip and op are the in and out points in frames. w and h are the artboard size. assets holds images and precomps. layers is an array of layer objects, drawn in order.
Everything you can see in the animation is a layer object in that array, or a layer object inside a precomp in assets. There is nothing else.
Where the mark sits
Layers are painted in array order and the mark has to land on top, so it goes at the front of the array. Exporters vary, so check both ends rather than assuming.
Its layer object has the same fields as everything else. ty is the type, 4 for a shape layer, 2 for an image, 5 for text. nm is the name, and that is the field that gives it away because nobody bothers hiding it. ind is the index. ks holds the transform. ip and op bound the frames it shows for.
That is the whole thing. No isWatermark boolean, no checksum over the rest of the document, nothing that a player could verify.
Why nobody ships a tamper proof one
The obvious question is why a vendor does not make this harder. They cannot, and the reason is built into the format, not laziness.
Lottie exists because it ships editable vector data. A few kilobytes that scale to any size and recolour at runtime. Flatten the mark into the artwork's pixels and you have destroyed the properties that made anyone want the format. Encrypt or sign part of the file and lottie-web will not parse it.
You could imagine a runtime that checked a signature before drawing. But the runtimes are open source and already inside millions of apps, so no single vendor gets to change what they enforce. The watermark is an honour system, and honour systems hold for legal and social reasons, not technical ones.
The one thing that actually breaks
Layer objects reference each other. A layer's parent field holds the ind of the layer it is transform parented to, which is how a designer makes several elements move as a group.
Delete a layer that something else was parented to and you have left a pointer into nothing. Some runtimes treat the child as unparented and it snaps to a new position. Some ignore it. This is the entire risk surface of removing a watermark and it is why the advice is always to play the file through once afterwards.
A decent editor resolves those references when it deletes. A hand edit in a text editor will not, so if you are going that route, search the file for the index you removed before you save.
The three places a mark can hide
Difficulty is decided entirely by which of these you have.
- A shape or text layer in the root
layersarray. Delete the object. The artwork underneath is a separate object and does not care. - A layer inside a precomp in
assets. Harder to find, identical to fix, because a precomp is just another layers array. - A raster image in
assets. The mark was composited into a PNG before export, so it shares pixels with whatever it sat on. The JSON has no way to separate them.
.lottie is a zip, not JSON
A .lottie file is a ZIP archive holding a manifest.json, one or more animation JSONs, and any binary assets. That is what makes it noticeably smaller over the wire.
Conceptually nothing changes. Practically you cannot open it in a text editor and start deleting. Unpack, edit the animation JSON inside, repack. Or use an editor that reads both containers and skip the archaeology.
If you are building tooling for this
Detection is mostly string matching on nm across the root layers and every precomp. That catches the known vendors and misses anything renamed. Matching on a hardcoded ind like 12345679 is even more brittle, and it will break the day Lottielab changes the number.
The part actually worth getting right is the parent cleanup. A remover that deletes the layer and leaves dangling parent values will sometimes produce a file that plays subtly wrong, and the user will blame their animation rather than your tool. Re-index, or at minimum null the orphans.