TwitterDownloaderX

Convert X GIFs (MP4) to real animated GIFs with ffmpeg

Why GIFs on X are actually MP4 videos, and practical ffmpeg recipes for turning them into small, good-looking animated GIFs, plus WebP and gifski alternatives.

By Karim · Published

If you've ever saved a "GIF" from X and found an .mp4 file in your downloads, nothing went wrong. That's what X actually serves. When you upload a GIF to X, it converts it into a short, silent, looping MP4 video. The player loops it and labels it "GIF", but the file is a video.

For most purposes that's an improvement: MP4 is far smaller than GIF and looks better. But sometimes you genuinely need a .gif, for an app that only accepts GIFs, a forum signature, a README, an email, or a presentation tool that won't loop video. This guide shows how to convert MP4 to GIF properly, so you don't end up with a grainy, banded, 40 MB mess.

We'll use ffmpeg, the free command-line video tool. If you've never used it, there's a short install section first.

Why naive conversion looks bad

The GIF format is from 1987. Each frame can use at most 256 colours, and compression is basic. Video, by contrast, can use millions of colours. When you convert video to GIF, something has to decide which 256 colours to keep.

If you run the simplest command, ffmpeg -i in.mp4 out.gif, ffmpeg uses a generic palette that isn't tuned to your clip. The result is often blotchy, with visible banding on gradients and skin tones, and it's huge, because it also keeps the full frame rate and resolution.

The fix is the two-step palette method: first analyse the clip to generate a palette of the 256 colours that suit it best, then encode the GIF using that palette. ffmpeg can do both in one command.

Installing ffmpeg

  • Windows: download a build linked from the ffmpeg website (the "Windows builds" links), unzip it, and add its bin folder to your PATH. Or install with a package manager: winget install ffmpeg.
  • Mac: with Homebrew, run brew install ffmpeg.
  • Linux: use your distribution's package, for example sudo apt install ffmpeg.

Check it works with ffmpeg -version.

The recipe that works for most clips

ffmpeg -i input.mp4 -vf "fps=12,scale=480:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" -loop 0 output.gif

What it does:

  • fps=12: reduces the frame rate to 12 frames per second. Most GIFs look smooth enough at 10–15 fps, and every frame you drop makes the file smaller.
  • scale=480:-1:flags=lanczos: resizes to 480 pixels wide, keeping the aspect ratio, with a high-quality scaling filter.
  • split[a][b]: makes two copies of the processed video stream.
  • [a]palettegen[p]: analyses the first copy and builds an optimised 256-colour palette.
  • [b][p]paletteuse: encodes the second copy using that palette.
  • -loop 0: loops forever (use -loop -1 for no loop, or a number for a fixed count).
Screenshot coming soon: side-by-side comparison of a naive conversion and the palette method on the same frame

Making it smaller

GIF size is roughly width × height × frames, so these are your levers:

  1. Trim it. Add -ss and -t before the input to take only the part you need:
ffmpeg -ss 1.5 -t 3 -i input.mp4 -vf "fps=12,scale=400:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" -loop 0 output.gif

This takes 3 seconds starting at 1.5 seconds.

  1. Go narrower. 320–400 px wide is plenty for most reaction GIFs.
  2. Lower the frame rate. Try 10 fps for slow content.
  3. Fewer colours. For simple graphics, limit the palette: palettegen=max_colors=64.
  4. Change dithering. Dithering scatters pixels to fake missing colours. It looks smoother but compresses worse. Options to try:
paletteuse=dither=bayer:bayer_scale=3
paletteuse=dither=none

dither=none gives the smallest files for flat graphics and screen recordings; Bayer dithering at scale 3–5 is a good compromise for video.

Better colours for footage with motion

If the scene changes a lot (a camera pan, a cut between shots), one palette for the whole clip can look poor at both ends. Generate the palette from changing pixels only, and let the encoder use different palettes as the scene changes:

ffmpeg -i input.mp4 -vf "fps=12,scale=480:-1:flags=lanczos,split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=diff_mode=rectangle" -loop 0 output.gif

stats_mode=diff focuses the palette on moving parts, and diff_mode=rectangle only re-encodes the region that changed between frames, which often shrinks the file noticeably for clips with a static background.

Useful variations

Crop to the interesting part

ffmpeg -i input.mp4 -vf "crop=600:600:200:60,fps=12,scale=360:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" -loop 0 square.gif

crop=w:h:x:y cuts a 600×600 region starting 200 px from the left and 60 px from the top.

Ping-pong (forward then backward) loop

ffmpeg -i input.mp4 -filter_complex "[0:v]fps=12,scale=400:-1:flags=lanczos,split[f][r];[r]reverse[rv];[f][rv]concat=n=2:v=1,split[a][b];[a]palettegen[p];[b][p]paletteuse" -loop 0 bounce.gif

Use this on short clips only. reverse holds every frame in memory.

Batch-convert a folder (Mac/Linux)

for f in *.mp4; do ffmpeg -i "$f" -vf "fps=12,scale=480:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" -loop 0 "${f%.mp4}.gif"; done

Alternatives worth knowing

  • gifski (gif.ski) is a free tool built specifically for high-quality GIFs, using smarter palette techniques. It's excellent when quality matters more than file size. It takes video input on the command line and has a Mac app.
  • Animated WebP is supported by modern browsers and most messaging apps. It's much smaller than GIF with better colour:
ffmpeg -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos" -loop 0 -c:v libwebp -quality 75 output.webp
  • Just keep the MP4. If the destination plays looping video (most websites with a <video autoplay loop muted playsinline> tag, Slack, Discord, X itself), the MP4 is smaller and better. Converting to GIF only makes sense when GIF is required.

Getting the source file right first

The quality of your GIF can't be better than the MP4 you start from, so a few minutes here pays off.

  • Start from the best variant. X's GIF posts are usually modest in resolution, but if a post lists more than one size, save the largest one and let ffmpeg do the scaling. Scaling down a larger source with the Lanczos filter gives a sharper result than starting small.
  • Don't convert a converted file. If a clip has already been through a messaging app or a screen recorder, it carries compression artefacts that the 256-colour palette will exaggerate. Use the original post or, for your own content, the file you originally uploaded.
  • Check the frame rate. Run ffprobe on the file to see its frame rate. If the source is 15 fps, asking for fps=24 only duplicates frames and makes the GIF bigger without making it smoother.
  • Look at the first and last frames. For a seamless loop, trim so that the last frame flows naturally into the first. A quarter of a second either way often makes the difference between a loop that feels smooth and one that visibly jumps.

A simple workflow we suggest

  1. Save the clip and play it once in VLC to decide the exact start and end times.
  2. Run the main recipe with your -ss and -t values at 480 px and 12 fps.
  3. Check the size. If it's too big, drop to 400 px, then to 10 fps, then try dither=bayer.
  4. If colours look poor, switch to the stats_mode=diff recipe.
  5. Keep the MP4 next to the GIF, so you can regenerate it with different settings later without hunting for the source again.
Screenshot coming soon: folder showing the source MP4 next to three GIF versions at different sizes, with their file sizes visible

Troubleshooting

"No such filter: palettegen". Your ffmpeg is very old or a minimal build. Install a current version.

The GIF is still huge. Check the three levers: width, fps, duration. A 6-second clip at 480 px and 12 fps is 72 frames; at 320 px and 10 fps it's 60 smaller frames, often less than half the size.

Colours flicker between frames. Try dither=bayer instead of the default, or use the stats_mode=diff recipe.

The GIF doesn't loop in my app. Make sure you used -loop 0. Some apps ignore loop settings and loop anyway; some never loop GIFs.

There's no sound. GIFs can't contain audio, and X GIFs never had any. If you need sound, keep it as MP4.

The output is squashed or stretched. Use -1 (or -2) for one dimension in scale so ffmpeg keeps the aspect ratio.

Using GIFs responsibly

Reaction GIFs are part of internet culture, but many come from films, TV, sport and other people's videos. Short reaction use is widely tolerated, but tolerated isn't the same as allowed, especially in marketing. If you're making a GIF for a brand or a product page, use footage you own or have licensed. And if you're turning someone's original animation into a GIF, credit them and ask first; our permission guide has templates.

Step by step on your device

Share this guide

XWhatsAppTelegram
All guides