
7 Ways to Turn a Video Into a GIF (and Why You Often Should Not)
Convert MP4 or MOV to GIF with ffmpeg palettes, gifski, screen recorders and browser tools. The three levers that control size, the frame rates GIF cannot represent, and when an MP4 wins.
GIF is a 1987 format with a 256-colour palette and no motion compensation. Every frame is stored more or less whole. A five-second clip that fits in 400 KB as an MP4 routinely lands at several megabytes as a GIF, showing the same thing with worse colour.
Here is the same five-second screen recording encoded seven ways, all at 480 pixels wide and 15 frames per second:
Same Five-Second Screen Recording, Seven Encodings
Static interface with one moving element. 480px wide, 15fps. Measured with ffmpeg.
The MP4 is sixteen times smaller than the smallest GIF and looks better. That gap is the argument this whole guide is built around, and it is why the last section explains how to go the other way.
It survives because it plays anywhere, autoplays silently, loops without a player, and pastes into Slack, chat apps and older email clients as an image rather than as media. Those are real advantages, and none of them are about quality.
This guide covers seven ways to make one, the three levers that control the result, and the specific cases where you should convert your GIF back into a video instead.
Pick Your Method First
| # | Method | Cost | Quality | Control |
|---|---|---|---|---|
| 1 | Browser converter | Free | Good | Frame rate and width |
| 2 | ffmpeg, single pass | Free | Poor | None |
| 3 | ffmpeg with a palette | Free | Best | Total |
| 4 | gifski | Free | Excellent | High |
| 5 | Screen recorders | Free | Good | Moderate |
| 6 | Photoshop | Subscription | Good | High |
| 7 | Online editors | Free | Good | Moderate |
The Three Levers
Every decision about GIF size comes down to three numbers. Nothing else moves the needle much.
Dimensions. Size scales with area, so halving the width quarters the pixel count. Going from 960 to 480 pixels wide is the single biggest saving available, and on a screen recording of a user interface it is usually invisible.
Frame rate. Size scales linearly. Video at 30 fps carries twice the data of the same clip at 15. For a UI demonstration, 12–15 fps reads as smooth. For a person moving, 20 is the floor before it looks stuttery.
Duration. Also linear, and the one people forget. Trimming three seconds off the front of a ten-second clip removes 30% of the file. Most GIFs contain two seconds of nothing at the start.
A fourth lever, the palette, changes quality far more than size — which is the subject of most of this guide.
Why the Obvious Command Looks Bad
Try the simple thing first, so the problem is concrete:
ffmpeg -i input.mp4 output.gif
The result is banded, muddy, and larger than it should be. That is not ffmpeg being careless. GIF allows 256 colours per frame, and without instructions ffmpeg falls back to a fixed, generic palette that has nothing to do with your footage. A sunset gets rendered from a web-safe colour cube.
The fix is to compute a palette from the actual video, then apply it. That is what methods 3 and 4 do, and it is the entire difference between an amateur GIF and a good one.
1. A Browser Converter
The no-install option, and it already uses the palette technique.
- MP4 to GIF
- MOV to GIF — for iPhone and screen recordings
Both run ffmpeg compiled to WebAssembly inside the browser page, so the video is never uploaded. They expose the two controls that matter, frame rate and output width, and apply palettegen and paletteuse behind the scenes with Lanczos scaling.
Because it runs on your own machine, conversion speed depends on your computer rather than on a queue, and there is no upload wait or file size cap beyond available memory.
When This Is the Right Answer
- A screen recording you want to paste into a pull request or a chat
- Footage you would rather not upload anywhere
- You want a good result without learning ffmpeg’s filter syntax
2. ffmpeg, Single Pass
Worth knowing so you can recognise it, and worth avoiding.
ffmpeg -i input.mp4 -vf "fps=12,scale=480:-1" output.gif
This gives you the size controls but not the palette, so colours remain poor. Use it only to check a clip length or a crop before doing the job properly.
3. ffmpeg With a Palette
The reference method. Everything else on this list is a wrapper around this idea.
The One-Liner
Good enough for most clips, and it needs no temporary file:
ffmpeg -i input.mp4 \
-vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop 0 output.gif
Reading it left to right: sample 15 frames a second, scale to 480 pixels wide keeping the aspect ratio, split the stream in two, generate a palette from one copy, and apply it to the other. -loop 0 means loop forever.
flags=lanczos matters. The default scaler is bilinear, which softens edges; Lanczos keeps text in a screen recording readable at half size.
The Two-Pass Version
More control, and better on clips with a static background:
# Pass 1: build the palette
ffmpeg -i input.mp4 \
-vf "fps=15,scale=480:-1:flags=lanczos,palettegen=stats_mode=diff" \
-y palette.png
# Pass 2: apply it
ffmpeg -i input.mp4 -i palette.png \
-lavfi "fps=15,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=sierra2_4a:diff_mode=rectangle" \
-loop 0 output.gif
stats_mode=diff tells palettegen to weight colours by what is moving rather than by what covers the most pixels. On a screen recording, a large grey background would otherwise dominate the palette and starve the small moving cursor and text of colours. This one flag noticeably improves most UI captures.
diff_mode=rectangle limits re-encoding to the rectangle that changed between frames, which cuts file size when most of the frame is still.
Dithering Is the Size Dial
paletteuse offers several dithering algorithms, and the choice moves file size more than any other palette setting.
Dithering works by scattering error across neighbouring pixels, which is noise. Noise differs between frames, and that defeats the frame-to-frame compression GIF depends on. So the more dithering you apply, the larger the file.
Measured on a four-second gradient-heavy clip at 480 pixels wide and 15 fps:
GIF Size by Dithering Algorithm
Same clip, same generated palette, only the dither changed. Gradient-heavy source, 480px, 15fps.
The spread here is about 18% between the extremes, not the factor of two often quoted. Ordered dithering with bayer produces a fixed pattern that repeats between frames, so it compresses better than error diffusion — but only on gradient content.
# Ordered dithering: a subtle crosshatch, and smaller on gradients
ffmpeg -i input.mp4 -i palette.png \
-lavfi "fps=15,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5" \
-loop 0 output.gif
On flat UI captures the ranking inverts. Repeating the same test on a screen recording of a mostly static interface gave none at 209 KB, sierra2_4a at 211 KB and bayer at 225 KB — the ordered pattern was the largest, because it imposes texture on areas that were perfectly flat.
The reliable rule across both: try dither=none first on anything with flat colour, and only reach for a dither if you can see banding.
Trimming and Cropping
# From 3.5s, for 4 seconds. -ss before -i seeks fast
ffmpeg -ss 3.5 -t 4 -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 out.gif
# Crop to a region: width:height:x:y, applied before scaling
ffmpeg -i input.mp4 -vf "crop=800:600:100:50,fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 out.gif
# Fewer colours, for a flat interface
ffmpeg -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=64[p];[s1][p]paletteuse" -loop 0 out.gif
Cropping to the part that matters beats scaling the whole frame down. A GIF of one dialogue box at full resolution is smaller and more useful than the whole desktop shrunk to fit.
The Frame Rates GIF Cannot Represent
This one catches everybody, and it explains GIFs that judder for no visible reason.
GIF stores the delay between frames in hundredths of a second, as an integer. So the only frame rates it can express exactly are those where 100 / fps is a whole number:
| fps | Delay | Exact? |
|---|---|---|
| 50 | 2 cs | Yes |
| 25 | 4 cs | Yes |
| 20 | 5 cs | Yes |
| 12.5 | 8 cs | Yes |
| 10 | 10 cs | Yes |
| 30 | 3.33 cs | No |
| 24 | 4.17 cs | No |
| 15 | 6.67 cs | No |
Ask for 30 fps and every frame is rounded to 3 or 4 centiseconds, giving an uneven cadence that reads as a stutter even though no frames were dropped.
Use 20, 25, 12.5 or 10. Twenty is the sweet spot for most motion; 12.5 is fine for interfaces. If a clip looks jerky after conversion and you cannot see why, the frame rate is the first thing to check.
There is a second, older quirk: many browsers treat a delay of 0 or 1 centisecond as 10, so a “100 fps” GIF plays at 10 fps. Anything above 50 fps is not worth attempting.
4. gifski
A dedicated GIF encoder that beats ffmpeg on quality, because it builds a palette per frame rather than one for the whole clip and blends between them.
# Install
brew install gifski
cargo install gifski
# From frames, the most reliable route
ffmpeg -i input.mp4 -vf "fps=20,scale=640:-1:flags=lanczos" frame%05d.png
gifski -o output.gif --fps 20 --quality 90 frame*.png
rm frame*.png
# Recent builds accept video directly
gifski -o output.gif --fps 20 --width 640 --quality 90 input.mp4
The difference shows on footage with rich colour — a sunset, skin tones, a colour-graded film clip — where a single 256-colour palette for the whole clip cannot hold everything. On flat UI captures, ffmpeg’s output is equivalent and faster.
The cost is speed and file size: gifski is slower and its output is often larger at the same dimensions, because it is spending bytes on colour accuracy. Lower --quality to trade back.
5. Screen Recorders That Output GIF Directly
If the source is your own screen, skip the video entirely.
- Kap (macOS, free, open source) — records a region straight to GIF with frame rate and size controls
- ScreenToGif (Windows, free, open source) — records, then opens a frame-by-frame editor where you can delete individual frames, add captions and set per-frame delays
- Peek (Linux, free) — deliberately minimal, records a rectangle to GIF
- LICEcap (Windows and macOS, free) — old, tiny, still works
ScreenToGif deserves particular mention because of the editor. Being able to delete the three seconds where you fumbled for a menu, without re-recording, is worth more than any encoder setting. It also lets you remove duplicate consecutive frames, which on a mostly-static recording cuts the size sharply.
Recording at the size you intend to publish avoids a scaling step and keeps text crisp.
6. Photoshop
File → Import → Video Frames to Layers, choose a range and optionally keep every second frame, then File → Export → Save for Web (Legacy) → GIF.
The export dialog exposes the palette directly: number of colours, dither percentage, and the reduction algorithm (Selective, Adaptive, Perceptual). Selective at 128 colours with 88% diffusion dither is a reasonable starting point.
Use it when the GIF needs editing anyway — text overlays, a logo, colour correction, hand-tuned frames. As a converter alone it is slower than every other method here and no better.
7. Online Editors
EZGIF is the one worth naming, because it is a genuine editor rather than a single-button converter. Convert, then use its optimiser to drop the colour count, remove every second frame, or crop, seeing the resulting file size after each step. That interactive loop is faster than re-running ffmpeg with different flags when you are hunting a size limit.
The usual caveat applies: the file is uploaded to a server. Fine for a clip from a public video, wrong for an internal product demonstration or anything under an agreement. Method 1 gives you a comparable result without leaving your machine.
Hitting a Size Limit
Platform ceilings are the usual reason people end up tuning. Slack refuses to animate above 2 MB. Many email clients and forums cap attachments lower still.
Work through these in order, stopping when you fit:
- Trim the clip. Almost every GIF has dead time at the start.
- Crop to the subject. Half the frame is usually irrelevant.
- Halve the width. 960 → 480 removes about 75% of the pixels.
- Drop to 12.5 fps. Exact, and smooth enough for interfaces.
- Switch to
dither=bayer:bayer_scale=5. Often halves the size. - Cut
max_colorsto 64 or 32. Free on flat UI colours. - Run
gifsicle -O3 --lossy=80over the finished file.
# The last-resort optimiser, and it is very effective
gifsicle -O3 --lossy=80 --colors 128 input.gif -o output.gif
gifsicle --lossy allows small per-pixel errors so that runs compress better. At 80 it is hard to see and often removes another third of the file.
If you have done all seven and still do not fit, the honest answer is that the clip should not be a GIF.
When to Do the Opposite
The conversion people search for less often, but need more.
# GIF to MP4 — typically 5 to 20 times smaller
ffmpeg -i input.gif -movflags faststart -pix_fmt yuv420p \
-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" output.mp4
Or use the GIF to MP4 converter in the browser.
-pix_fmt yuv420p is required for playback in Safari and on older Android devices. The scale=trunc(iw/2)*2 expression rounds the dimensions to even numbers, because H.264 cannot encode odd ones — a GIF that is 501 pixels wide otherwise fails to encode at all.
On a web page, replace the <img> with a video that behaves exactly like a GIF:
<video autoplay loop muted playsinline poster="fallback.jpg">
<source src="clip.webm" type="video/webm">
<source src="clip.mp4" type="video/mp4">
</video>
muted and playsinline together are what allow autoplay on mobile browsers. This loops silently and identically to a GIF, at a fraction of the bytes. Animated GIFs are a recurring cause of poor Largest Contentful Paint scores — see image optimization for Core Web Vitals.
Animated WebP and animated AVIF are the other modern options, both supported across current browsers, both far smaller than GIF, and both usable in a plain <img> tag. Our guide to migrating from GIF covers the full comparison.
Where GIF Still Wins
Keep the GIF when the destination demands it:
- Slack, Discord and most chat clients, which render it inline and loop it automatically
- Email, where video support remains unreliable across clients
- Content systems and forums that accept images but not media
- Anywhere the file will be re-shared by people, since a GIF survives copy and paste
Everywhere else — your own website above all — use a video or a modern animated format.
Summary
The Seven Methods
| # | Method | Use it when |
|---|---|---|
| 1 | Browser converter | Quick, private, no ffmpeg syntax |
| 2 | ffmpeg single pass | Only for checking a crop or a length |
| 3 | ffmpeg with a palette | The default for anything that matters |
| 4 | gifski | Colour-rich footage, quality above size |
| 5 | Screen recorders | The source is your own screen |
| 6 | Photoshop | The GIF needs real editing |
| 7 | Online editors | Interactively hunting a size limit |
Checklist
- ✅ A palette was generated from the footage, not assumed
- ✅ The frame rate is 20, 25, 12.5 or 10 — never 30 or 15
- ✅
flags=lanczoswas used, so text stayed readable - ✅ The clip was trimmed and cropped before anything else
- ✅
stats_mode=diffwas used on screen recordings - ✅ Dithering was tuned, since it changes size by about half
- ✅
gifsicle -O3 --lossyran over the finished file - ✅ The web destination got a video or WebP, not a GIF
Use method 3 with fps=20, scale=480:-1:flags=lanczos and a generated palette. That single command covers most of what people want, and the remaining tuning is the dithering flag.
Related Resources
Related Guides
Migrating from GIF to Modern Animated Formats
Screenshots and Documentation Images: Optimization Guide
9 Ways to Reduce Image File Size Without Losing Quality
12 Image Optimization Mistakes That Slow Down Your Website
12 Free Image Tools Every Web Developer Should Bookmark
Image Optimization for Core Web Vitals