How to Add Lottie Animations to a WordPress Site

Putting a working Lottie animation inside a live WordPress theme is a technical problem that’s different from picking a nice motion file off a gallery. You need to export the JSON, load a lightweight player with wp_enqueue_script, upload the animation file, embed it with a custom block or template tag, control its playback, then compress and lazy-load it before launch.
That’s seven steps. I’ve done this sequence dozens of times while building custom WordPress themes for clients who wanted a breathing hero section, an animated navigation bar icon, or a moving logo. This guide shows you the exact process I follow, not how it appears in marketing screenshots.
If you landed here searching for navigation bar animation, this turns that inspiration into working code nobody else covering this phrase actually shows you.
What You Need Before You Start
Get these four things sorted before opening any file. Skipping this step is why developers get stuck halfway through Step 3.
A Lottie JSON file
You either export your own animation from a design tool or download a ready-made one. If you’re sourcing rather than building, LottieFiles hosts the largest public library of free and premium Lottie animations, all in the JSON format the player expects.
Access to your theme files or child theme
You need FTP, an SFTP client, or your host’s file manager, plus permission to edit functions.php and template files. On a live production site, work in a child theme. Editing a parent theme directly means losing every change the next time it updates.
A code editor and file access
VS Code, Sublime, or the WordPress admin’s built-in theme editor will work, though I don’t recommend editing live files through wp-admin on production sites. Pair your editor with FTP or SSH so you can roll back quickly if something breaks.
Pre-Flight Checklist
- Lottie JSON file downloaded or exported, under 300KB where possible
- Child theme active (not editing the parent theme directly)
- FTP, SFTP, or file manager access confirmed
- A staging site or backup in place before editing
functions.php - Know which theme file controls the section where the animation will live (header.php, front-page.php, or a block template)
Step 1: Export the Motion Design as a Lottie JSON File
Export your animation from Adobe After Effects using the Bodymovin plugin, which converts After Effects layers into the JSON format that Lottie players read.
Exporting from After Effects with Bodymovin
Bodymovin is the original export plugin for the Lottie format and remains the standard bridge between After Effects and web-ready animation files. Install it from the After Effects Extensions panel, open your composition, select the render settings panel, and choose Bodymovin as the render destination. Adobe documents the workflow in its After Effects scripting and extension guidance, and the export itself takes seconds once the plugin is configured.
Keep your composition simple before exporting. Avoid embedded video layers, excessive masks, and heavy gradients. Bodymovin converts everything to vector shapes and text. Complex effects either flatten badly or bloat the file. Shape layers, solid colors, and simple keyframed transforms export the cleanest.
What a clean JSON export should look like
A well-optimized Lottie export for web use:
- Stays under 300KB for a short loop (under 5 seconds)
- Uses shape layers instead of rasterized images
- Has no embedded fonts unless absolutely required
- Contains a reasonable frame rate (24 or 30fps, not 60fps for simple UI motion)
- Opens cleanly in the free LottieFiles preview tool without console errors
If your exported file is several megabytes, go back into After Effects and simplify before moving forward. Optimizing at the source always beats trying to compress a bloated file after the fact.
Step 2: Install a Lottie Player in Your WordPress Theme
Load the Airbnb-originated Lottie web player into your theme so the browser knows how to render the JSON file as an animation.
Using the lottie-player web component (CDN vs. self-hosted)
The lottie-player web component, maintained under the Lottie/Airbnb open-source project on GitHub, is the fastest way to get a working player without custom JavaScript. You have two hosting choices:
| Hosting method | Setup speed | Performance control | Best for |
|---|---|---|---|
| CDN (jsDelivr or unpkg) | Fastest, one script tag | Depends on third-party uptime | Prototypes, small sites, quick client demos |
| Self-hosted in theme | Slightly more setup | Full control over caching and versioning | Production sites, agencies, performance-sensitive builds |
I self-host on every client project. It removes a third-party network request, pins an exact library version, and avoids surprise breaking changes if the CDN file updates upstream.
Registering the script with wp_enqueue_script
Never paste a raw <script src="..."> tag directly into your header. WordPress has a built-in system documented in the WordPress Developer Handbook’s wp_enqueue_script reference. Using it correctly avoids duplicate-loading conflicts with plugins that also load jQuery or animation libraries.
Add this to your child theme’s functions.php:
function ivorymiracle_enqueue_lottie_player() {
wp_enqueue_script(
'lottie-player',
get_stylesheet_directory_uri() . '/js/lottie-player.js',
array(),
'2.0.5',
true
);
}
add_action( 'wp_enqueue_scripts', 'ivorymiracle_enqueue_lottie_player' );
The true at the end loads the script in the footer, which keeps it from blocking your page’s initial render. This detail matters for page speed.
Step 3: Upload and Reference the Lottie File Correctly
Place the JSON file somewhere your theme can reliably reach it, then reference that exact path in your embed code.
Where to store the JSON file in a custom theme
Keep animation files in a dedicated /assets/lottie/ folder inside the child theme, alongside images and other static assets. This keeps version control clean if you use Git and separates animation files from general media library clutter.
Referencing the file path correctly
You have two options, each with different behavior:
- Theme directory: Use
get_stylesheet_directory_uri() . '/assets/lottie/animation.json'. This path is stable, versioned with your theme code, and doesn’t change if someone reorganizes the media library. - Media library: Upload through wp-admin’s Media > Add New, then copy the generated URL. This is easier for non-developers to swap out later, but WordPress sometimes appends query strings or serves the file through a CDN plugin that mishandles the
.jsonMIME type.
If you use the media library route and the file returns a 404 or downloads instead of loading, your host’s server configuration may block the .json extension for security reasons. Add an .htaccess MIME type exception or ask your host to allow JSON uploads. This single issue causes a large share of "my animation won’t load" support tickets.
Step 4: Embed the Animation in a Template or Block
Drop the lottie-player element wherever you want the animation to appear, either through the block editor or directly in a template file.
Adding lottie-player via the custom HTML block
In the Gutenberg block editor, add a Custom HTML block and paste:
<lottie-player
src="/wp-content/themes/your-child-theme/assets/lottie/animation.json"
background="transparent"
speed="1"
style="width: 200px; height: 200px;"
loop
autoplay>
</lottie-player>
The block editor sometimes strips custom tags it doesn’t recognize when you switch between visual and code view too many times. Save the block, reload the page, and check the front end rather than trusting the editor preview alone. If the tag disappears, disable the "Convert to blocks" prompt and keep the block in raw HTML mode.
Embedding directly in a theme template file
For a navigation bar animation or a header element you want on every page, put the markup directly in header.php or the relevant template part:
<div class="site-logo-animation">
<lottie-player
src="<?php echo esc_url( get_stylesheet_directory_uri() . '/assets/lottie/nav-icon.json' ); ?>"
background="transparent"
speed="1"
loop
autoplay
style="width: 48px; height: 48px;">
</lottie-player>
</div>
Wrapping the path in esc_url() follows WordPress’s own security and escaping guidelines. This matters if the file path ever includes dynamic or user-influenced data.
This video from LottieFiles shows the HTML and JavaScript embed process end to end, which pairs well with the template method above: https://www.youtube.com/watch?v=_oKeoxGPzBw&pp=ygUwSG93IHRvIEFkZCBMb3R0aWUgQW5pbWF0aW9ucyB0byBhIFdvcmRQcmVzcyBTaXRl
Step 5: Control Playback, Loop, and Trigger Behavior
Decide whether your animation should play automatically, loop forever, or wait for a scroll or hover event before firing.
Autoplay and loop attributes
The lottie-player component accepts simple boolean attributes:
autoplaystarts the animation as soon as the page loadslooprepeats the animation indefinitelyspeed="1.5"adjusts playback ratemode="bounce"reverses direction each time it completes, instead of restarting from frame one
Leave autoplay off for anything below the fold. There’s no reason to burn CPU cycles animating something the visitor hasn’t scrolled to yet.
Triggering playback on scroll or hover
For a scroll-triggered effect, remove the autoplay attribute and use JavaScript with the Intersection Observer API, a native browser feature for detecting when an element enters the viewport:
const player = document.querySelector('lottie-player');
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
player.play();
observer.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
observer.observe(player);
For hover-triggered navigation bar animation, skip the observer and bind directly to mouse events:
const navIcon = document.querySelector('.site-logo-animation lottie-player');
navIcon.addEventListener('mouseenter', () => navIcon.play());
navIcon.addEventListener('mouseleave', () => navIcon.stop());
Comparison: lottie-player vs. Bodymovin plugin vs. SVG fallback
| Method | Best use case | Performance impact | Setup complexity |
|---|---|---|---|
| lottie-player web component | Custom themes, full control over triggers | Low, if file is optimized and lazy-loaded | Moderate, requires enqueueing and markup |
| Bodymovin WordPress plugin | Non-developers wanting a shortcode-based embed | Moderate, plugin adds its own script bundle | Low, install and activate |
| Static SVG fallback | Accessibility-first builds, users with reduced-motion preference | Lowest, no JS animation engine needed | Low, but loses motion entirely |
I default to the lottie-player web component on every custom theme build because it gives me direct control over triggers and file hosting. If a client wants a no-code option and already relies on plugins for most site functionality, a Bodymovin-compatible plugin from the WordPress.org Plugin Directory is a reasonable shortcut, though you give up fine-grained control over playback timing.
Step 6: Optimize the File for Page Speed
Compress and lazy-load your Lottie file so the animation enhances the page instead of slowing it down.
Reducing JSON file size
Run your exported file through the free optimization tool at LottieFiles, which strips redundant keyframes and unused data without changing how the animation looks. If you built the file in After Effects, simplifying shape paths and removing unused layers before export gets you most of the way there already.
Lazy loading the animation
Don’t load the player script or the JSON payload until it’s needed. A simple approach: keep wp_enqueue_script registered but defer initialization of below-the-fold animations using the same Intersection Observer pattern from Step 5. Only fetch the JSON src attribute once the element scrolls into view.
File Size & Load Targets
- Final JSON file under 300KB for any animation that autoplays on load
- Under 100KB for anything inside a navigation bar or header, since that region loads first
- Player script deferred to the footer via
wp_enqueue_script‘s footer argument - Below-the-fold animations lazy-initialized, not loaded on first paint
- Page tested through Google PageSpeed Insights after adding the animation, comparing the score against a pre-animation baseline
If PageSpeed Insights flags render-blocking resources after you add the animation, it’s almost always the script loading in the header instead of the footer, or the JSON file loading before the user ever scrolls near it.
Step 7: Test Across Devices and Browsers
Confirm the animation renders correctly and doesn’t drag down performance on the devices your actual visitors use.
Mobile performance checks
Test on a mid-range Android device, not just the newest iPhone. Lottie animations rely on JavaScript execution, and lower-powered mobile processors can stutter on complex vector animations that run smoothly on desktop. If you see dropped frames, reduce the shape complexity or lower the frame rate in the original export.
Cross-browser rendering checks
The lottie-player web component works in all evergreen browsers, but always verify in actual Safari on macOS or iOS, not just Chrome DevTools’ device emulation. Safari has historically handled web components and certain CSS properties differently than Chromium-based browsers. Check Firefox as well if your audience includes a meaningful share of that browser.
Troubleshooting Common Issues
This table covers failure points that actually come up in real support tickets and client builds.
| Symptom | Likely Cause | Fix |
|---|---|---|
| Animation doesn’t appear at all | Script not enqueued, or wrong file path | Check browser console for 404s; confirm wp_enqueue_script fires on the right hook |
| Block editor strips the embed tag | Custom HTML block converted to a core block automatically | Keep the block in "Edit as HTML" mode; avoid toggling preview repeatedly |
| Animation loads but never plays | Missing autoplay attribute, or JS trigger never fires |
Confirm the Intersection Observer or event listener is actually bound after DOM load |
| Page feels sluggish after adding animation | JSON file too large, or script loading in header | Compress the file via LottieFiles; move script to the footer with the enqueue function’s last argument |
| Animation plays fine on desktop, stutters on mobile | Composition too complex for lower-powered devices | Simplify shape layers in After Effects; reduce frame rate to 24fps |
| File downloads instead of rendering | Server blocks .json MIME type |
Add an .htaccess exception or contact your host |
| Animation looks blurry or pixelated | Raster image layers embedded instead of vector shapes | Rebuild the composition using shape layers only |
| Works in Chrome, breaks in Safari | Web component polyfill missing on older Safari versions | Confirm the lottie-player script version supports your minimum Safari target |
Frequently Asked Questions
What do I need before I start adding a Lottie animation to WordPress?
You need an exported Lottie JSON file, access to your theme files (ideally a child theme), and a code editor with FTP or file manager access. Skipping the child theme step is the most common reason updates wipe out custom animation code.
How do I export a motion design as a Lottie JSON file?
Build the animation in Adobe After Effects using shape layers rather than raster images, then render it through the Bodymovin plugin, which converts the composition into the Lottie JSON format.
What is the Bodymovin plugin used for in After Effects?
Bodymovin is the export plugin that translates After Effects compositions into Lottie’s JSON animation format, making the file readable by web-based Lottie players.
How do I install a Lottie player in a WordPress theme?
Load the lottie-player web component either from a CDN or self-hosted in your theme, then register it properly using wp_enqueue_script inside your child theme’s functions.php file.
What is the lottie-player web component?
It’s a browser-native custom element, built on the open-source Lottie library originally released by Airbnb, that renders Lottie JSON animations without requiring a heavy JavaScript framework.
How do I use wp_enqueue_script to load a Lottie player script?
Register the script inside a function hooked to wp_enqueue_scripts, pointing to the script’s file path, and set the final parameter to true so it loads in the footer instead of blocking the page header.
Where should I upload my Lottie JSON file in WordPress?
Store it inside your child theme’s assets folder for stability and version control, or upload it through the media library if you want non-developers to swap the file later.
Should I store the Lottie file in the media library or the theme directory?
The theme directory is more stable and developer-friendly; the media library is easier for content editors but occasionally runs into MIME type or CDN plugin conflicts with .json files.
How do I embed a Lottie animation using the custom HTML block?
Add a Custom HTML block in the Gutenberg editor, paste the lottie-player markup with its src attribute pointed at your JSON file, and save without repeatedly toggling between visual and code views.
Can I embed a Lottie animation directly in a theme template file?
Yes. Place the lottie-player markup inside header.php or another template part, wrapping the file path in esc_url() for proper escaping.
How do I control autoplay and loop behavior for a Lottie animation?
Add the autoplay and loop boolean attributes directly to the lottie-player tag; remove autoplay if you want the animation to wait for a scroll or hover trigger instead.
How do I trigger a Lottie animation on scroll?
Remove the autoplay attribute and use the Intersection Observer API in JavaScript to call the player’s .play() method once the element enters the viewport.
How do I trigger a Lottie animation on hover?
Bind mouseenter and mouseleave event listeners to the element and call the player’s .play() and .stop() methods accordingly.
How do I reduce the file size of a Lottie JSON file?
Simplify the After Effects composition before export by using shape layers instead of raster images, then run the exported file through LottieFiles’ free optimization tool.
How do I lazy load a Lottie animation in WordPress?
Defer fetching the JSON file’s src attribute until the element scrolls near the viewport, using the same Intersection Observer pattern used for scroll-triggered playback.
Will a Lottie animation slow down my WordPress site’s page speed?
It can, if the file is oversized or the script loads in the header. Kept under 300KB and loaded in the footer with lazy initialization, the performance impact is minimal and verifiable with Google PageSpeed Insights.
How do I test a Lottie animation across different browsers?
Check actual Safari and Firefox installations, not just Chrome DevTools emulation, since web component support and rendering behavior differ between browser engines.
How do I test a Lottie animation on mobile devices?
Test on a mid-range Android phone in addition to a modern iPhone, since lower-powered processors reveal frame drops that don’t show up on flagship hardware.
What should I do if my Lottie animation isn’t loading in WordPress?
Check the browser console for 404 errors on the JSON file path, confirm the enqueue function is firing, and verify your host allows .json file uploads if you’re using the media library.
Why does the WordPress block editor sometimes strip my embed code?
Gutenberg occasionally converts a Custom HTML block into a different block type when toggling views, which strips unrecognized tags. Keep the block explicitly in HTML edit mode.
What’s the difference between using lottie-player and the Bodymovin WordPress plugin?
The lottie-player web component gives you direct control over hosting, triggers, and file paths, while a Bodymovin-based plugin offers a faster, no-code setup with less flexibility over playback behavior.
Should I use an SVG fallback if Lottie fails to load?
Yes, for accessibility and reduced-motion users. A static SVG fallback ensures the layout still looks intentional if JavaScript fails or the visitor has motion preferences disabled at the OS level.
Do I need a child theme to safely add Lottie animations?
Not strictly, but it’s strongly recommended. Editing a parent theme’s functions.php or template files directly means losing every change the next time the theme updates.
Can Lottie animations be used safely in a WordPress navigation bar?
Yes, provided the file stays small (ideally under 100KB) since navigation elements load first on every page view, and the trigger is set to hover or a subtle loop rather than an aggressive autoplay that distracts from navigation itself.
Next Steps
This guide covered the technical build. For the fuller conceptual grounding on what a Lottie file actually is and how the format differs from GIFs or video, read about what Lottie animation is for the complete definition.
If you’re converting an existing motion design or Figma prototype into a working WordPress theme from scratch, I’ve documented the process I use in converting a motion design into a WordPress theme, and the original case study behind that workflow is at this Figma to WordPress case study.
If your project needs more than a single animated element, whether a full custom theme build or ongoing motion design support, my team at Ivory Miracle handles both the code and the animation from a single workflow. You’re not stitching together a freelance designer, a separate developer, and a plugin that half-works.
If you’re still deciding whether to build this yourself or hand it off, this breakdown of hiring a freelance WordPress developer walks through what to look for either way.
Sources
- Lottie/Lottie-web GitHub Repository
- WordPress Developer Handbook: wp_enqueue_script
- WordPress Developer Handbook: Security and Escaping
- WordPress.org Plugin Directory
- Adobe After Effects Scripting and Extensions Documentation
- LottieFiles
- Google PageSpeed Insights
Related: motion design with Lottie
My right hand does not know how much my left hand has given, and vice versa. Over the years, I have given to orphanages, street children and their families, the elderly, women seeking livelihood opportunities, widows, and people who are on the fringes of society. My logic is simple: I never want anyone to feel as though they have been forgotten by society. Sometimes it does not take much. People on the streets have actually smiled at me simply because I gave them a cookie. That smile can stay with you much longer than you expect. No one should feel forgotten. I’m a little like the city that raised me. My favorite food is beef pares, tenderly cooked beef simmered for several hours until the meat practically melts in your mouth. Its taste cannot easily be contained by a poverty of vocabulary when it is cooked just right, and the stew is simply the icing on the cake. In a strange way, it reminds me of the beautiful ways God has arranged my heart through my unique experiences in life. Manila itself feels like a melting pot, no pun intended, of food, beverages, languages, art, people, contradictions, and real life. I think I have become a little like the city that raised me. Read About Me.



Join the conversation
Good work gets better when people bring thoughtful questions, ideas, and perspective.