SVG animations and Lottie files are excellent in the browser. They scale without losing quality, they are tiny compared to video files, and they can be driven by JavaScript or triggered by scroll events. The problem appears the moment you try to use them anywhere else.
Email clients strip JavaScript and CSS animations. Open Graph preview images on social platforms are static — you cannot embed an animated SVG as an og:image. Many CMS platforms render SVG files as static images, ignoring their animation data entirely. And Lottie JSON files — the output from After Effects via the Bodymovin plugin — require the LottieFiles player or the lottie-web library to play, which means they are completely invisible to anyone who receives one as a standalone file.
The solution is exporting your animations to video formats that play everywhere: GIF, WebM, or MP4. Each serves different use cases, and each requires a different approach depending on what your source animation actually is.
Understanding the Source Format
The conversion workflow you use depends on what you are starting with.
SVG animations use CSS keyframes, SMIL animations, or JavaScript (typically GSAP or AnimeJS). The animation lives in code — not rendered frames — which means you cannot simply open the file in a video editor and export it.
Lottie files are JSON documents that describe After Effects animations using the Lottie specification. They require a runtime (the lottie-web library or the LottieFiles player) to render and play.
CSS animations are the most common: a web component, a loading spinner, a hero section animation — all driven by CSS @keyframes and applied via class names.
All three source types share the same fundamental problem: they are not rendered video. Converting them to video requires either a browser rendering pass, a dedicated export tool, or a screen capture workflow.
Output Format Comparison
Before choosing a conversion workflow, decide which output format you need. The choice is not cosmetic — each format has real constraints that affect where and how the animation can be used.
| Format | Transparency | Email Safe | File Size (vs GIF) | Browser Support | Social Media |
|---|---|---|---|---|---|
| GIF | Yes (1-bit) | Yes | 1x (baseline) | Universal | Most platforms |
| WebM (VP9) | Yes (alpha) | No | 0.2–0.4x | Chrome, Firefox, Edge | Limited |
| WebM (VP8) | Yes (alpha) | No | 0.3–0.5x | Chrome, Firefox, Edge | Limited |
| MP4 (H.264) | No | No | 0.15–0.3x | Universal | All platforms |
| APNG | Yes (8-bit) | Partial | 0.5–0.8x | Modern browsers | No |
GIF: Universal but Expensive
GIF plays everywhere — every email client, every browser, every social platform since 1987. That universality comes at a painful cost: the GIF format uses a palette of only 256 colors, and its compression algorithm was designed for simple graphics, not video content. A 3-second animation that weighs 40 KB as a Lottie file might exceed 2 MB as a GIF at the same resolution.
GIF transparency is also limited to a single transparent color, not an alpha channel. This creates jagged edges on smooth rounded shapes — the classic "GIF aliasing" problem visible around transparent text and circular elements.
Use GIF when: the animation must display in email, when the recipient environment is unknown, or when you need the absolute widest compatibility with no JavaScript or modern browser dependency.
WebM: Best Quality on the Web
WebM with VP9 video and an alpha channel is the ideal format for web animations that replace GIFs. The file size difference is dramatic — a 1 MB GIF can often become a 150 KB WebM with identical or better visual quality. VP9 handles the large flat color areas in motion graphics far better than GIF's LZW compression.
The key advantage over MP4 is transparency support. VP9 with alpha channel (sometimes called WebM with transparency) allows the animation to play over any background color without encoding a visible background frame. This is critical for logo animations, overlays, and UI animations where the background is dynamic.
The limitation is Safari. Safari on older macOS versions and iOS devices below iOS 14 does not support WebM. The standard pattern is to serve WebM to supported browsers and fall back to MP4 or APNG for Safari.
<!-- Transparent animation that falls back gracefully -->
<video autoplay loop muted playsinline>
<source src="animation.webm" type="video/webm">
<source src="animation.mp4" type="video/mp4">
<!-- Last resort fallback -->
<img src="animation.gif" alt="Animation">
</video>
MP4: Social Media and Background Video
MP4 with H.264 encoding is the most practical format for social media uploads, background video loops, and anywhere you need guaranteed playback across all devices. Twitter, Instagram, LinkedIn, Reddit, and YouTube all accept MP4. The format is compact, hardware-accelerated for playback on every device, and compatible with every video player.
The limitation is the absence of transparency. MP4 cannot have a transparent background — any transparent areas in your source animation must be replaced with a solid background color when exporting to MP4.
Use MP4 when: uploading to social media, embedding as a <video> background on a website, sharing through any platform or messaging app, or when you need hardware-accelerated smooth playback at 60fps.
Converting Lottie Files to Video
Lottie files have the best tooling support of the three source formats.
Method 1: LottieFiles Web Exporter
The easiest approach for simple exports. Go to LottieFiles.com, upload your JSON file, and use the Export menu. The web exporter renders the animation in a browser context and can output GIF, MP4, and various image formats. Quality is good for most use cases.
Limitations: limited control over output quality, no alpha channel support for MP4 export, and the online tool requires uploading your animation to a third-party server.
Method 2: After Effects Re-Export
If you have After Effects and the Bodymovin plugin (the source of most Lottie files), you can export directly to video from After Effects using the Adobe Media Encoder. This produces the highest quality output because you are working from the original After Effects composition, not a rendered intermediate.
For a WebM with alpha channel from After Effects:
- Render the composition from After Effects as an image sequence (PNG with alpha) — this is the lossless intermediate
- Use FFmpeg to assemble the image sequence into WebM with VP9 alpha
# Assemble PNG sequence into WebM with VP9 alpha channel
ffmpeg -framerate 60 -i frame_%04d.png \
-c:v libvpx-vp9 -pix_fmt yuva420p \
-b:v 0 -crf 15 \
-auto-alt-ref 0 \
animation.webm
The -pix_fmt yuva420p flag is the critical setting that enables the alpha channel. Without it, FFmpeg defaults to yuv420p, which strips transparency.
Method 3: Lottie-to-Video via Puppeteer
For automated pipelines — converting batches of Lottie files, CI/CD integration, or server-side rendering — browser automation via Puppeteer is the most reliable approach.
const puppeteer = require("puppeteer");
const path = require("path");
const fs = require("fs");
async function lottieToPNG(lottieJsonPath, outputDir, frameCount, fps = 60) {
const browser = await puppeteer.launch({
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
const page = await browser.newPage();
// Get animation duration from Lottie JSON
const lottieData = JSON.parse(fs.readFileSync(lottieJsonPath, "utf-8"));
const durationSeconds = lottieData.op / lottieData.fr; // out-point / frame-rate
const totalFrames = Math.ceil(durationSeconds * fps);
await page.setViewport({ width: 800, height: 800, deviceScaleFactor: 2 });
// Serve a minimal HTML page with the Lottie player
await page.setContent(`
<!DOCTYPE html>
<html>
<head>
<style>
* { margin: 0; padding: 0; }
body { background: transparent; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js"></script>
</head>
<body>
<div id="lottie-container" style="width:800px;height:800px;"></div>
<script>
const animData = ${fs.readFileSync(lottieJsonPath, "utf-8")};
window.anim = lottie.loadAnimation({
container: document.getElementById("lottie-container"),
renderer: "svg",
loop: false,
autoplay: false,
animationData: animData,
});
</script>
</body>
</html>
`);
await page.waitForFunction(() => window.anim && window.anim.isLoaded);
fs.mkdirSync(outputDir, { recursive: true });
for (let i = 0; i < totalFrames; i++) {
const progress = i / (totalFrames - 1);
await page.evaluate((p) => window.anim.goToAndStop(p, true), progress);
await page.screenshot({
path: path.join(outputDir, `frame_${String(i).padStart(4, "0")}.png`),
omitBackground: true, // Preserves transparency
});
}
await browser.close();
console.log(`Captured ${totalFrames} frames to ${outputDir}`);
}
// Usage
lottieToPNG("./animation.json", "./frames", 120, 60);
Pro Tip: Always capture frames at 2x deviceScaleFactor for retina quality, then scale down in FFmpeg if needed. The FFmpeg scale filter with lanczos downscaling preserves sharp edges in motion graphics far better than capturing at native resolution.
After capturing frames, assemble into your target format:
# PNG sequence to GIF with high-quality palette
ffmpeg -framerate 60 -i frames/frame_%04d.png \
-vf "fps=30,scale=400:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=256:stats_mode=diff[p];[s1][p]paletteuse=dither=bayer:bayer_scale=5" \
animation.gif
# PNG sequence to MP4
ffmpeg -framerate 60 -i frames/frame_%04d.png \
-c:v libx264 -pix_fmt yuv420p -crf 18 \
-movflags +faststart animation.mp4
# PNG sequence to WebM with transparency
ffmpeg -framerate 60 -i frames/frame_%04d.png \
-c:v libvpx-vp9 -pix_fmt yuva420p \
-b:v 0 -crf 18 -auto-alt-ref 0 \
animation.webm
Converting CSS Animations to Video
CSS animations are browser-rendered, which means your capture tool must be a browser — or something that embeds a browser engine.
Playwright Browser Capture
Playwright has a native video recording feature that captures exactly what the browser renders. For CSS animations, this is often the most accurate method:
const { chromium } = require("playwright");
async function captureAnimation(htmlFile, outputPath, durationMs = 3000) {
const browser = await chromium.launch();
const context = await browser.newContext({
viewport: { width: 800, height: 600 },
recordVideo: {
dir: "./video_output/",
size: { width: 800, height: 600 },
},
});
const page = await context.newPage();
await page.goto(`file://${path.resolve(htmlFile)}`);
// Wait for animation to complete
await page.waitForTimeout(durationMs);
await context.close(); // Triggers video save
await browser.close();
// Video saved to ./video_output/
}
Playwright records as WebM by default. Convert to other formats with FFmpeg afterward.
Screen Recording as a Last Resort
For animations that cannot be automated — GSAP timelines with complex interactions, Three.js scenes, anything that requires user input — screen recording software is the fallback. OBS Studio, macOS Screenshot, or Screenflow can capture the browser window at 60fps. Record in MKV (crash-safe), then convert to your target format.
The downside is no transparency support and dependency on manual timing. Reserve this for one-off exports where automation is impractical.
Optimizing GIF Output
GIF file size is dominated by palette generation and dithering choices. The FFmpeg palettegen and paletteuse filter combination significantly outperforms single-pass GIF encoding.
# Two-pass GIF generation with optimized palette
# Pass 1: Generate palette from the full animation
ffmpeg -i animation.mp4 \
-vf "fps=15,scale=480:-1:flags=lanczos,palettegen=stats_mode=diff" \
palette.png
# Pass 2: Use generated palette for final GIF
ffmpeg -i animation.mp4 -i palette.png \
-filter_complex "fps=15,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" \
animation.gif
The stats_mode=diff setting in palettegen builds the palette based on the differences between frames rather than the entire frame content. This dramatically improves palette allocation for animations where only a portion of the frame changes — which is most motion graphics.
diff_mode=rectangle in paletteuse reuses unchanged pixels from the previous frame rather than re-encoding them, reducing file size by 20–50% in animations with static backgrounds.
Pro Tip: Reducing frame rate is the single most effective way to shrink a GIF. A 60fps animation converted to 15fps for GIF output loses almost no perceptible quality in a web context — animations are usually short enough that the lower frame rate is unnoticeable. This alone reduces file size by 4x compared to a 60fps GIF.
For the full GIF production workflow and optimization techniques, see our detailed guide on GIF optimization for web performance. You can also use our online GIF maker for quick conversions without command-line tools.
Platform-Specific Output Settings
| Target | Format | Max Size | Notes |
|---|---|---|---|
| Email (marketing) | GIF | 1 MB recommended | Keep under 600px wide |
| Twitter/X | MP4, GIF | 15 MB GIF / 512 MB MP4 | MP4 preferred, auto-loops |
| MP4 | 5 GB | Max 10 min duration | |
| Instagram feed | MP4 | 4 GB | 1:1 or 4:5 aspect for feed |
| Slack | GIF, MP4 | 1 GB | GIF for inline animation |
| Webflow / WordPress | WebM, MP4 | Host-dependent | WebM first, MP4 fallback |
| Open Graph image | Static PNG | — | Animations not supported |
| Web background video | WebM, MP4 | — | Autoplay + muted required |
Note that Open Graph images are always static — no matter what format you upload, social crawlers capture a single frame. If you need the "featured thumbnail" of an animated sequence to look intentional, render a specific frame from your animation as PNG and use that as the OG image.
Format Conversion on ConvertIntoMP4
For one-off conversions and quick experiments, our tools handle the heavy lifting without any command-line setup. The GIF maker converts video files to optimized GIF with palette optimization built in. To go the other direction, convert GIF to MP4 for social-ready output.
Browse the full GIF converter for all GIF-related conversions, or explore the WebP converter if your workflow involves static image optimization alongside animation export. For a complete overview of image and animation formats, the image converter hub covers all supported format pairs.
For more context on when WebM is the right choice over MP4, see our breakdown in WebM vs MP4 comparison. And if your starting point is a raster image that you want to vectorize before animating, the image vectorization guide covers the SVG conversion workflow from PNG and JPEG sources.
Frequently Asked Questions
Can I convert a Lottie file without using After Effects?
Yes. The Puppeteer/Playwright approach described above renders Lottie animations entirely in a headless browser using the lottie-web library — no After Effects license required. LottieFiles.com also provides a free online exporter for basic conversions.
Why does my GIF look banded and grainy compared to the original animation?
GIF is limited to 256 colors, and converting a smooth gradient or photographic element to a 256-color palette always produces visible banding. Use the two-pass FFmpeg palette approach described above, which builds a custom palette from your specific animation rather than using a generic one. For content with gradients, consider switching to WebM with a transparent alpha channel — it handles smooth color transitions without any banding.
My WebM with transparency works on Chrome but not Safari. How do I handle this?
Use the <video> element with both WebM and MP4 sources, in that order. Safari will skip the WebM source and use the MP4. If transparency is required on Safari, use APNG as a third fallback: <source src="animation.apng" type="image/apng">. APNG is supported in Safari and provides true alpha channel transparency, though file sizes are larger than WebM.
What frame rate should I use for exported animations?
Match the original animation frame rate for MP4 and WebM exports — typically 24fps, 30fps, or 60fps depending on the source. For GIF exports, drop to 10–15fps to control file size. Human perception of animation smoothness in short looping animations is forgiving at lower frame rates, especially for UI animations and logo reveals.
Can I convert an SVG animation to video programmatically at scale?
Yes, and the Puppeteer approach in this guide is the standard method for batch conversion. For server-side rendering in CI/CD pipelines, puppeteer with --no-sandbox runs reliably in Docker containers. Process multiple files in parallel using Promise.all() with a concurrency limit (typically 3–5 parallel browser instances depending on available memory).
Conclusion
The path from SVG, CSS, or Lottie animation to video is more involved than a simple file conversion — but it is fully automatable once you choose the right toolchain. Browser automation with Puppeteer or Playwright handles the rendering step that converters cannot skip, and FFmpeg handles the encoding step with precise control over quality and file size.
For most use cases: capture PNG frames at 2x resolution, assemble into WebM with transparency for web use, generate a GIF for email and maximum compatibility, and produce an MP4 for social media uploads. Keep each format's constraints in mind — palette limitations for GIF, Safari compatibility for WebM, no transparency for MP4 — and choose the output that matches your deployment environment.
Use our GIF maker and video converter hub for quick one-off conversions, and the FFmpeg recipes in this guide for repeatable automated workflows.



