On-device AI — professional-grade, fully private.

Optimize GIF

Optimize a GIF frame by frame — same animation, fewer bytes.

  • No upload
  • Lossless by default
  • Timing preserved
  • Duplicates removed

Drop a GIF here

GIF, animated WebP or APNG

Frame structure
Frame differencing
0

How different a pixel must be from the last frame before it is sent again. 0 is exact.

Off writes every frame whole again — what other tools call coalescing.

Duplicate frames
Duplicate frames

A removed frame's time is added to the frame that stays, so the animation never speeds up.

Lossy runs
0

Lets a pixel join the run of colour beside it, which is what the compression rewards.

Background
Background

Flattening gives up the see-through background and gets frame differencing back.

Palette
128
Dithering

How to optimize a GIF

Remove the redundancy between an animated GIF's frames without changing its size, its speed or its colours.

  1. 1

    Add your GIF

    Drag an animated GIF onto the drop area, or click to browse. Animated WebP and APNG work too. The file is read on your device and never uploaded.

  2. 2

    Leave the defaults for a lossless pass

    Frame differencing is on and duplicate frames are removed only when they are byte-identical. Nothing about the picture changes on these settings — the file simply stops storing what it already stored.

  3. 3

    Reach for a slider only if you need more

    Difference tolerance forgives near-identical pixels between frames. Lossy runs joins near-identical pixels within a frame. Both trade a little accuracy for real size, and both show you exactly what they cost.

  4. 4

    Check the report, then download

    The result panel names the frames kept, the share of the canvas each stored frame covers and the duration in and out. Press Download when the numbers say what you wanted.

What a GIF optimizer removes

Almost every GIF in circulation is larger than it needs to be for a reason that has nothing to do with quality. The format has allowed a frame to cover only the rectangle that changed since 1989, and to mark the rest of its pixels as "what is already on screen here is still correct" — and most encoders never use either. So a twenty-frame screen recording of a static page with a moving cursor stores that static page twenty times. Optimising removes the repetition and touches nothing else: the same dimensions, the same number of frames a viewer sees, the same playback speed and, on the default settings, the same colours down to the last value.

Store only the pixels that change between frames, delete frames that repeat and merge their time into the frame that stays, and share one colour table across the animation.

Reads GIF, animated WebP and APNG. Writes a standard GIF89a at the same dimensions, the same duration and — where the palette fits — the same colours.

What that is worth, measured

  • Frame differencing. On this tool's reference animation — a gradient background with one small square crossing it — 196,091 bytes stored whole becomes 48,131 stored as differences. On the hundred-frame version, 4,776,638 becomes 1,172,755. Both are 4.07x, and both are colour-exact.
  • Duplicate frames. A twelve-frame animation of four distinct pictures comes out as four frames carrying the same twelve frames' worth of time. A six-frame animation of one picture comes out as one frame holding all 600 ms.
  • Cropping a see-through frame. A sticker whose opaque content fills a fifth of the canvas is stored as a fifth of the canvas. On this pack's transparent test animation that is 191 bytes from 19,473 — a hundred-fold reduction with the transparency intact.
  • Nothing you did not ask for. No resize, no frame-rate cut, no palette reduction unless you move a slider. If re-encoding cannot beat the file you gave us, you get your file back and are told so.

Frame differencing, and why most GIFs do not use it

A GIF is not a stack of pictures. It is a canvas plus a list of instructions, and each instruction is allowed to paint a rectangle anywhere on that canvas, at any size, with any of its pixels marked see-through so that whatever is underneath shows instead. A frame that changes a 30-pixel patch can be stored as a 30-pixel patch. The reason so few files do this is that writing one is much harder than writing the other: the encoder has to keep a model of what a decoder would currently be showing, compare against that rather than against the previous source frame, and get the disposal method right or the result smears. It is easier to write every frame whole, so most encoders do.

What happens to each frame

  • Composite. Every frame is drawn onto a canvas of the animation's logical size, honouring its offset, its disposal method and its transparency, so what gets compared is the picture a viewer would actually see rather than the patch that was stored.
  • Scan once. A single pass answers everything the encode needs: which frames are repeats, whether there is any transparency anywhere, how many distinct colours there are, and the sample the palette is built from. Answering them separately would mean four passes over every pixel.
  • Map to one shared table. Where the source's colours fit a table, that exact list becomes the palette. Where they do not, one is derived across the whole animation rather than from the first frame, so colours do not shift as it plays.
  • Difference, then compress runs. Each frame is compared against a running model of the decoded canvas, reduced to the rectangle that changed, and the unchanged pixels inside that rectangle are marked see-through. Only then does the optional lossy pass run, so it can never damage the difference.

The invariant every implementation of this gets wrong

When a duplicate frame is removed, its display time has to go somewhere. Drop ten frames of a twenty-frame animation at 100 ms each and forget to merge the delays, and you are left with ten frames of 100 ms — a two-second animation that plays in one second, at double speed. The output is a valid GIF. Nothing errors. It simply is not the animation that went in. Here the total duration in and the total duration out are compared on every run and a mismatch is raised as an error rather than returned as a smaller file, and both numbers are printed on the result panel so you never have to take it on trust.

Removing duplicate frames without changing the animation

Content-based frame removal is different from dropping every second frame, and the difference is the whole point. Dropping every Nth frame is blind: it removes frames that showed something new alongside frames that did not, and the result stutters immediately. Removing duplicates only deletes frames a viewer could not have distinguished from the one before, and merges their time into it — so a screen recording where the cursor pauses for half a second loses ten stored frames and none of its motion. If what you want instead is a lower frame rate, that lever lives on the compressor, where it belongs alongside the other quality trades.

Two modes, and the threshold that separates them

  • Identical only. Byte-for-byte repeats, and nothing else. This is the default because it cannot change what anyone sees — the frames being removed were, pixel for pixel, already on screen.
  • Near-identical. A similarity threshold from 80% to 100%. At 98%, a frame matching at least 98% of the previous kept frame is treated as a repeat. Useful on footage with faint noise, where nothing is ever byte-identical and a great deal is visually unchanged.
  • Off. Every frame is kept whatever it holds. Worth choosing when the frame count itself matters — some editors and some sprite pipelines index frames by number.

Why the comparison is against the last frame kept

Compare each frame against the one immediately before it and a slow fade passes the threshold at every single step, so the whole animation collapses to its first frame while every individual comparison looked perfectly reasonable. Comparing against the last frame that was KEPT bounds the error instead: whatever the threshold is, that is the most a viewer can ever be shown that the recording did not contain, and it does not accumulate. It is a smaller number of frames removed on drifting material and it is the right trade, because the failure it prevents is silent.

Measured results

Every number below comes from this tool's own test pack, on fixtures committed alongside it and regenerated by a script rather than checked in as mysterious binaries. Each output is read back by three independent implementations: libvips for the rendered animation, gifsicle for the frame structure, and a structural reader written for the pack that walks the file's blocks and never runs the decompressor.

The levers, in order of what they are worth

  • Frame differencing 4.07x on the reference animation at both 20 and 100 frames, with a measured mean colour error of 0.000 of 255. This is the whole reason the tool exists.
  • Duplicate removal 12 frames to 4, and 6 to 1, on the two dedicated fixtures — with 1,200 ms in and 1,200 ms out, and 600 ms in and 600 ms out.
  • Difference tolerance at 40 1,172,755 bytes to 487,196 on the hundred-frame reference. A further 2.41x on top of the lossless pass.
  • Lossy runs at 60 1,172,755 bytes to 478,644 on the same file. Comparable to the tolerance slider and visible in a different way — within a frame rather than across frames.
  • Speed A hundred frames at 480x270, decoded, scanned, differenced and written, in 252 to 380 ms on the reference device.

Against gifsicle, the engine most online optimizers run

The frame rectangles this tool produces are identical to gifsicle -O3's on every fixture measured — same offsets, same sizes, same colour-table sizes — which says the structural decisions agree. On total file size we match or beat it on eight of ten fixtures and lose on two, by 0.03% and 3.1%, entirely inside the compressed payload rather than the structure. Two things we do that it does not: remove near-duplicate frames, and tell you when re-encoding made your file bigger instead of handing the bigger file back.

Optimize or compress — which one you actually want

These are two different jobs and picking the wrong one wastes quality you did not need to spend. Optimising removes redundancy: the file gets smaller and the animation is unchanged, so there is no reason not to do it. Compressing removes information: fewer pixels, fewer colours, fewer frames per second, until a file size you name is reached. Start here. If the result is still too big, the compressor takes over from where this leaves off.

A short decision list

  • Start with the optimizer, always. It costs nothing visually and it is often enough on its own. There is no sense throwing away colours before removing pixels that were being stored twice.
  • Use the compressor when a number is the requirement. "Under 8 MB for Discord", "under 256 KB for a custom emoji". It searches resolution, palette and frame rate together until it hits the number.
  • Use the resizer when the dimensions are wrong. This tool will never change them. If the animation is 1920 wide and the column is 700, that is a resize, and doing it first makes everything else cheaper.
  • Come back here afterwards. Optimising the output of a resize or a compress usually finds more, because those tools rebuild the frames and this one is what removes the repetition from them.

GIF Compressor · GIF Resizer

Getting the most out of it

The default settings are chosen to be the ones nobody has to think about: frame differencing on, duplicates removed only when byte-identical, both lossy sliders at zero, dithering off. That combination cannot change what anyone sees, which is why it is the default — an optimizer that quietly altered the picture would be a compressor with a misleading name. Everything below is about when to move away from it.

By material

  • Screen recordings and UI demos. The best case there is. The background is static, so the differences are tiny, and pauses in the recording produce byte-identical frames that cost nothing to remove. Defaults, and expect several times.
  • Video-derived footage. Nothing is ever byte-identical because of the compression noise underneath, so switch duplicate removal to near-identical at 98% and move the difference tolerance up. Both are aimed at exactly this material.
  • Stickers and logos on a transparent background. Frame differencing is unavailable — the format only has one see-through index and the background is using it — but frames are still cropped to their opaque content, which is usually worth more here than differencing would have been.
  • Photographic and heavily dithered GIFs. There may be nothing to remove, and the tool will say so rather than hand you a larger file. Reduce the colour count, or use the compressor.

What the optimizer opens, and what it writes

The input list is closed and enforced at the file dialog rather than at the engine, so a file this tool cannot open is refused in milliseconds with a route to the tool that can — instead of being accepted and failing later behind a spinner.

  • GIF in. Animated or single-frame, interlaced or not, with a global palette or a different local palette on every frame. Sub-rectangle frames at an offset are composited onto the full canvas before anything is compared.
  • Animated WebP and APNG in. Both are read by our own demuxers on every browser rather than by a native decoder, so frames and timing are identical everywhere. Both carry far more than 256 colours, so a palette is derived for them and the result is not colour-exact.
  • GIF out, always. A standard GIF89a with one global colour table, per-frame delays, sub-rectangle frames, disposal methods and a Netscape loop extension.
  • Anything else is refused with a route. A video is sent to Video to GIF, a still image to the GIF Maker.

What the tool reads

GIF is decoded natively where the browser has a decoder for it and by our own reader everywhere else, so an animation opens the same way in every browser rather than arriving as its first frame with no error. Animated WebP and APNG always take our own reader, which is what keeps frame counts and timing identical across engines. What a file claims by its name is ignored: the first sixteen bytes decide, so a `.gif` that is really something else is refused at intake rather than three minutes later.

Size and batch limits

  • Free. One file up to 50 MB and up to 300 frames. Every structural lever is included — frame differencing, duplicate removal, transparency preservation, cropped frames — because those are what the tool is, and a free plan without them would be a demonstration rather than a tool. The colour table is capped at 128 entries.
  • Pro. Up to 50 files at once, downloaded as one ZIP, no file-size or frame limit beyond what your device can hold, and the full 256-colour table that makes a colour-exact pass possible on any GIF.
  • No dimension cap on either plan. The optimizer never changes dimensions, so a ceiling on them would be a limit on nothing. Both plans return the animation at exactly the size it arrived.
  • The limit both plans share. Every frame is expanded to full colour while it is being worked on, so a memory budget bounds the job before it starts rather than letting the tab stop responding while the progress ring keeps turning.

How the optimisation runs on your device

Nothing is uploaded. The file is decoded frame by frame on your machine, scanned once for repeats, transparency and colour count, mapped to a single shared palette, differenced against a running model of what a decoder would be showing, and written out as a standard GIF89a. All of it runs in a background thread so the page keeps painting throughout, and the palette mapping — the per-pixel part, and the expensive one — runs on your graphics hardware where it is available.

Why the same file optimises identically every time

  • A deterministic quantiser. Median cut, not the randomised neural quantiser most GIF libraries use — and, where the source's colours fit, no quantiser at all. The same input with the same settings always produces byte-identical output.
  • Identical results on every path. The graphics-accelerated and processor paths are required to produce the same bytes, not merely similar ones. Verified by running all three and comparing hashes: a path that chose a different palette entry would show as colour flicker between frames, which is far more visible in an animation than one wrong pixel is in a still.
  • Checked against implementations that share no code. The rendered animation is read back by libvips, the frame structure by gifsicle, and the file's blocks by a reader written for the test pack. A file our own code both writes and reads proves nothing.
  • Optimising twice changes nothing. Running the tool over its own output returns the same file and reports it as already optimised, which is the property that says the first pass finished the job.

Palette mapping is hardware accelerated where your device supports it, and the accelerated and fallback paths are verified to produce byte-identical output. Frame structure is checked against gifsicle and the rendered animation against libvips, neither of which shares any code with this tool. Measured on the reference device: 100 frames at 480x270 optimised in 252 ms, 4.07x smaller, with a mean colour error of 0.000 of 255. It all runs on your device, not our servers.

Frequently asked questions

What does a GIF optimizer actually do that a compressor does not?

A compressor makes the picture cheaper: fewer colours, fewer pixels, fewer frames per second. An optimizer makes the file stop repeating itself. A GIF frame is allowed to cover only the rectangle that changed and to mark the rest of its pixels as "what is already on screen here is still correct", and most GIFs in the wild do neither — every frame is stored whole, including the background that has not moved since the first one. Measured on this tool's own test animation, a static background with one moving square: 196,091 bytes stored whole against 48,131 bytes stored as differences. Same twenty frames, same dimensions, same colours, a quarter of the file.

Is this lossless?

On the default settings, for a GIF whose colours fit one table, yes — and that is measurable rather than a figure of speech. The tool counts the source's distinct colours and, when they fit, uses that exact list as the palette instead of deriving a new one, so every pixel maps to the entry it already had. Composited frame by frame against the source with an independent image library, the mean colour error across this pack's GIF fixtures is 0.000 of 255. Two things break that, both stated on screen when they happen: a source with more colours than one table can hold (an animation with a different palette on every frame), and either of the two lossy sliders being moved off zero.

Will removing duplicate frames speed my animation up?

No, and this is the single thing worth checking on any tool that offers it. When a frame is deleted its display time is added to the frame that stays, so the total playback duration is identical before and after. The tool refuses to return a result if it is not: the duration in and the duration out are compared, and a mismatch is an error rather than a smaller file. It matters because getting it wrong produces a perfectly valid GIF that simply plays too fast, and nothing about the file looks wrong.

What is the difference between removing identical frames and near-identical ones?

Identical means byte-for-byte: a frame that is a pixel-perfect copy of the one before it. That is common in screen recordings, where the cursor pauses, and it is free to remove. Near-identical uses a similarity threshold — at 98%, a frame that matches at least 98% of the previous kept frame's pixels is treated as a repeat. The comparison is always against the last frame that was KEPT, not the last one seen, which is what stops a slow drift collapsing an entire animation one imperceptible step at a time. It also means the error a viewer sees is bounded by the threshold you set, once, rather than accumulating.

Why did the tool say my GIF was already optimized?

Because re-encoding it came out no smaller than the file you gave us, so you got your own file back rather than a slightly larger one. That happens on material with no redundancy to remove — photographic noise that changes across the whole canvas every frame, or a GIF that has already been through an optimizer. It is the honest answer, and it is not the usual one: most tools in this category hand back the larger file with a green tick. If you need that file smaller anyway, the size has to come from quality, which is what the GIF Compressor does.

What do the two lossy sliders do, and which should I move first?

They work in different directions. Difference tolerance is temporal: it decides how different a pixel has to be from the previous frame before it is worth sending again, so it makes the changed rectangles emptier. Lossy runs is spatial: it lets a pixel join the run of colour beside it when the two are close enough, which is what LZW compression is built to reward. Move difference tolerance first — it costs less visually because the difference is spread across time, and on this pack's hundred-frame reference it takes the file from 1,172,755 bytes to 487,196 at a setting of 40.

Will my transparent background survive?

Yes, and it is detected rather than assumed. GIF has no alpha channel: one palette index is nominated as see-through. The catch is that frame differencing needs that same index to mean "unchanged", so the two cannot both be used — which is why an optimizer that composites onto an opaque canvas before re-encoding hands back a sticker with a black box behind it. Here every frame is scanned for see-through pixels, and when any are found the background wins: frames are written whole, with disposal set to restore the background, and the panel says frame differencing is unavailable and why. Whole does not mean full-size — each frame is still cropped to its opaque content, which on this pack's transparent test animation gives 191 bytes from 19,473.

Can I undo an optimisation — turn the frames back into full pictures?

Yes. Turn frame differencing off and every frame is written whole again, which is what other tools call coalescing and usually charge a separate page for. It is occasionally necessary: some older editors and a few social platforms mis-handle sub-rectangle frames, and a few will only accept a GIF whose frames are all the same size. Expect the file to grow by roughly the amount the difference was saving.

How does this compare to gifsicle?

Gifsicle is the engine behind most online GIF optimizers, so it is the right thing to be measured against rather than described against. On this pack's fixtures the frame RECTANGLES the two tools produce are identical — same offsets, same sizes, same colour-table sizes — and on total file size we match or beat gifsicle -O3 on eight of ten fixtures. Two of them we lose by a small margin, entirely in the compressed payload rather than the structure: 0.03% on one and 3.1% on another. Where we are ahead is content: gifsicle has no near-duplicate frame removal, and it does not tell you when re-encoding made your file bigger.

Does the optimizer change the dimensions?

Never. There is no scale control and no output ceiling on either plan, and the result panel reports the source's dimensions and the output's side by side so the claim is checkable rather than asserted. If you do want a different size, that is the GIF Resizer's job, and it preserves the timing the same way this does.

Why does the palette only hold 256 colours, and what happens if my GIF has more?

That is the format, not the tool: a GIF colour table has at most 256 entries. An animation can exceed it by carrying a different local table on each frame — and that is exactly what frame differencing cannot work with, because a difference compares palette indices and indices only mean the same thing across a shared table. So one global table is written, always. When the source's colours fit it they are used exactly; when they do not, a palette is derived across the whole animation rather than from the first frame, and the panel tells you the source held more colours than one table can carry.

Can I optimize several GIFs at once?

On Pro, yes — up to 50 files in one go, downloaded together as a single ZIP, with every file getting the same settings. That is the actual chore this solves: a folder of documentation clips or a set of custom emoji, each of which is individually quick and collectively an afternoon. The free plan handles one file at a time, at full frame-level optimisation, up to 50 MB and 300 frames.