Compress GIF

Shrink an animated GIF in your browser. Presets cut frame rate, width and palette size, and the tool never hands back a file bigger than your original.

🌐 Español

Drop your file here (.gif)

🔒 Private by design: your files are processed locally in your browser and never uploaded to any server.

Three levers, and nothing else to turn

A GIF is not a video file wearing a different extension. The format stores every frame as an indexed-color bitmap with LZW compression layered over it, and it has no motion estimation, no inter-frame prediction and no bitrate control of any kind. Everything a modern codec uses to make a file small is simply absent.

That leaves exactly three numbers you can change, and this tool sets all three from a single Compression preset dropdown, with Light leaving the width alone and moving only the other two:

Frame rate is usually the biggest single win, because it removes whole frames rather than shaving bits off each one. Palette size is the one people forget, and it is often the reason a flat, screen-recorded GIF shrinks further than expected.

Inside the two-pass palette that does the work

The module builds one FFmpeg filter graph and passes it as a single -filter_complex argument. Written out, the balanced preset produces fps=12,scale=min(iw\,480):-1:flags=lanczos,split[a][b];[a]palettegen=max_colors=128[p];[b][p]paletteuse. The backslash in there is not a typo: the comma inside min() has to be escaped or FFmpeg reads it as the separator between two filters.

Reading that left to right: the stream is resampled to a constant frame rate, downscaled with the Lanczos filter, then split into two identical branches. One branch is analysed by palettegen, which surveys the whole clip and picks the best 128 colors for it. The other branch waits, then gets those 128 colors applied by paletteuse. It is a two-pass technique running inside one command, and it is why the output does not suffer the muddy, dithered look you get from letting the GIF encoder fall back on a generic web-safe palette.

Wrapping the width in min() is what makes this downscale-only. A GIF already narrower than the cap keeps its own width, so nothing is ever blown up to meet the preset. The height is left as -1, meaning FFmpeg computes it from the aspect ratio, which is why only the width is genuinely bounded.

Compressing a GIF, start to finish

  1. Drop your file on the box above, or use Choose a file. Only .gif is accepted here, and anything else is rejected before processing starts.
  2. Set Compression preset. Start at Balanced (recommended) unless you already know you are fighting a hard upload limit.
  3. Click Compress GIF. The progress bar tracks the FFmpeg run, and Cancel stops it and clears the box.
  4. Read the before and after sizes printed above the download, then click the download button. If the saving is not enough, click Process another and try the next preset down.

Choosing a preset by where the GIF is going

A GIF headed for a chat bubble or a forum reply is being displayed at a few hundred pixels wide no matter what you upload, so Balanced costs you nothing visible and saves a lot. A GIF that is the actual subject of a post, like a UI walkthrough where the reader needs to see small text, is worth keeping at Light and solving the size problem another way.

If the clip started life as video, it is usually better to go back to the source than to compress the GIF. Converting the MP4 to GIF with its own frame rate and width controls gives you one lossy step instead of two stacked on top of each other. Trimming the framing helps more than most people expect too, since dead space still costs palette entries and pixels: the GIF cropper does that with a visual selection box across every frame. And a clip that is simply too long reads fine at double speed, which the GIF speed changer does by rescaling every frame’s timestamps, then rebuilding the palette the same way this page does.

When you get your original file back

Re-encoding does not always shrink a GIF. If your source is already at 8 fps and you pick Balanced, the fps=12 filter will duplicate frames to reach 12, and the result can be larger than what you started with. The module checks for exactly that: after the encode it compares the two sizes, and if the new file is not smaller it returns your original bytes instead.

The download is still named with a -compressed suffix, so the honest way to read the result is the size line, not the filename. Identical numbers mean the guard fired and this method has nothing left to give on that file.

The GIFs this cannot rescue

Photographic content is the hard case. A GIF of real video footage, with gradients and film grain, is being forced through a 256-color ceiling that was never designed for it, and dropping to 64 colors turns smooth skies into visible bands. No preset here fixes that, because the constraint is the format.

Long GIFs are the other one. Frame count multiplies everything, and a thirty-second loop at any watchable frame rate is a large file by construction. If the destination will take video at all, turning the GIF into an MP4 puts the same animation on a codec that can encode motion rather than store every frame whole, and you can squeeze the result further with the MP4 compressor. The rest of the routes are in the video tools section. Keep the GIF only when the platform genuinely requires one.

Frequently asked questions

Does the palette really matter, or is it just the frame rate?

It matters, and it is the lever most GIF compressors skip. Each preset passes a different max_colors value to FFmpeg's palettegen filter (192, 128 or 64), which builds a custom palette from the colors your GIF actually contains rather than reusing a generic one. Fewer palette entries means fewer bits per pixel before LZW even starts, so a flat-colored screen recording can shrink noticeably from the palette change alone.

My GIF came back exactly the same number of bytes. Is that a bug?

No, that is the guard working. After the encode the tool compares the new file's size against your original and, if the new one is not smaller, it returns your original bytes instead. You still get a download named with a "-compressed" suffix, but it is a byte-for-byte copy of what you dropped in. It usually means the source was already optimized, or already below the preset's frame rate.

Can I set a specific target size in megabytes?

No. The three presets are fixed combinations of frame rate, width cap and palette size, and none of them is a size target. GIF gives an encoder no bitrate control at all, so the only way to hit a number is to try a preset, look at the before and after sizes the tool prints, and step down a level if it is still too big.

Will the compressed GIF still loop forever?

The module passes FFmpeg exactly one flag, a filter graph, and never sets a loop count. The loop behaviour of the output is therefore whatever FFmpeg's GIF muxer writes by default rather than a copy of what your source file specified. In practice that means a play-once GIF can come back as a looping one. If the loop count is critical, check the result before you publish it.

Why does the tool cap width but not height?

The scale filter it builds is written as min(iw,W) for the width with an automatic height, where W is 480 on Balanced and 320 on Aggressive, and Light adds no scale filter at all. The aspect ratio is preserved and only the width is bounded. A very tall portrait GIF can therefore end up taller than the preset's number even though its width was reduced. The min() wrapper also means a GIF narrower than the cap is left at its own width, never stretched up to meet it.

Is a GIF still the right format for what I am doing?

Often not. If the destination accepts video at all, an H.264 MP4 of the same clip will usually be dramatically smaller than any GIF of it, because a real codec can encode the difference between frames instead of storing each one whole. Compress the GIF when the platform genuinely demands a GIF, such as a forum or a chat client that will not autoplay video inline.

Related tools