FFmpeg recipe

FFmpeg: Convert MP4 to GIF with Custom Palette

Default ffmpeg GIF uses the web palette and looks posterized. Custom palette extraction picks the optimal 256 colors for your specific clip.

Command

ffmpeg -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -y output.gif
Prefer no terminal?
Use the Video to GIF in your browser
Open Video to GIF →

What each flag does

-iInput file. Can be a video, audio, or image. Repeat for multiple inputs.
-yOverwrite output file without confirmation.
-vf "..."Filter chain: set FPS, resize, then split → palettegen → paletteuse for optimal color quality.
fps=1515 fps is the GIF sweet spot — smooth enough, file size half of 30 fps.
scale=480:-1Resize to 480 px wide, height auto. Smaller width = much smaller GIF.
palettegenBuild a custom 256-color palette tuned to this clip.

Notes & gotchas

  • Drop FPS to 12 or width to 360 for stricter file size budgets.
  • Add dither=bayer:bayer_scale=5 to paletteuse for smoother gradients (slightly larger file).

Check it worked

ffprobe -v error -show_entries stream=width,height,nb_frames -of csv=p=0 output.gif

The width you asked for, and frames equal to duration times frame rate. A huge frame count means the fps filter did not apply.

What to change

Width matters more than fpsHalving the width quarters the pixels. Dropping 15 fps to 12 saves a fifth. Resize before you cut frames.
Always generate a paletteA single-pass GIF uses a generic 216-colour palette and looks it. palettegen plus paletteuse builds one from your clip.
Dithering trades noise for bandingbayer is smaller and patterned; sierra2_4a is smoother and larger because neighbouring frames stop compressing well.

If it fails

The GIF is enormous, sometimes larger than the video.

Why: GIF stores every frame as its own palettised image with no compression between frames.

Fix: Cut the duration first, drop to 10 or 15 fps, and reduce the width. Those three together usually cut the file by an order of magnitude.

Colours look banded or dirty.

Why: The default palette is generic rather than derived from this clip.

Fix: Use the two-pass form: palettegen into a PNG, then paletteuse with that palette, which builds 256 colours from the clip itself.

Related recipes