Turn a video into a GIF
A GIF is the one format that plays itself, loops without being asked, and survives being pasted into a chat window with no player required. This endpoint takes a video clip and produces exactly that, optimised so the file isn't ten times heavier than it needs to be.
Run it online
Run this on our servers with your account. Free tools run in your browser; this one bills your KIT balance per the price above.
Why GIF refuses to die
Born in 1987 as a compact image format for early dial-up web pages, GIF became a video format almost by accident once browsers started looping its multi-frame support automatically. Decades later it's still the one moving-image format every platform renders inline without a player, a click, or a permissions prompt — a chat app, a forum post, a product page. video.gif exists because that convenience never got replaced, even though the format itself is nearly forty years old and technically outdated for anything else.
What the request produces
POST /video/gif with the source clip, and you get an immediate task_id while the conversion runs. Once ready, the optimised GIF arrives through a signed webhook call or waits at a signed link valid for 24 hours — either way, what comes back is a file already trimmed for size, not a raw frame-by-frame dump of the original video.
The size problem GIF was never built to solve
GIF's color palette is capped at 256 colors per frame and it has no true inter-frame compression the way video codecs do, so a naive conversion balloons in size fast — a ten-second clip can easily outweigh the source video it came from. Getting a usable GIF means trimming duration, capping frame rate, and choosing a palette carefully, all before the format's own limitations turn a small clip into an unshareable multi-megabyte file. That optimisation work happens as part of the conversion, not as a separate step you have to chase down afterward.
Fitting into a content workflow
GIFs tend to come at the end of a chain rather than the start: trim a highlight, maybe resize it down, then convert that short result to GIF, so the conversion step is working with seconds of footage rather than a full recording. Because pricing is a flat per-request fee plus a small per-minute rate on the source, feeding the endpoint an already-short clip keeps both the cost and the output file size where they should be, instead of paying to process minutes of footage that never make it into the final loop.
What you can do with it
Product demo loop for a landing page
A SaaS marketing team converts a five-second interaction clip into a looping GIF that autoplays on a landing page without needing a video player.
Chat and forum reactions
A community platform lets users turn a short uploaded clip into a GIF that pastes directly into chat threads and comment sections.
Changelog and release notes
A product team converts a short screen recording of a new feature into a GIF embedded directly in release notes and documentation pages.
Email-safe motion graphics
A marketing team converts a brand animation into a GIF for email campaigns, since most inboxes won't autoplay embedded video but will render a GIF.
FAQ
How do I convert a video to GIF with the API?
POST the source video to /video/gif, keep the returned task_id, and retrieve the optimised GIF by webhook or a signed link valid for 24 hours.
Is the video to GIF API free?
No, there is no free tier or trial; it costs $0.077 per request plus $0.0045 per minute of source video, and a failed conversion is never charged.
Why are GIFs so much bigger than the source video?
GIF has no efficient inter-frame compression and a limited 256-color palette per frame, so without optimisation the file size grows quickly compared to a properly compressed video.
Does the endpoint optimise the GIF automatically?
Yes, the conversion trims frame rate and palette choices for a smaller, web-ready file rather than returning a raw frame dump.
Should I trim my clip before converting it to GIF?
Yes, shorter source clips produce smaller, faster GIFs and cost less, since pricing includes a per-minute rate on the source video.
Is this endpoint live yet?
It's in deployment now, so check the endpoint status before sending production traffic since it isn't accepting jobs at this moment.
Can I convert many clips to GIF in bulk?
Yes, submit one async task per clip and collect each GIF by webhook as it finishes, which suits batch content pipelines.
Is my video stored after the GIF is generated?
No, the source video and the resulting GIF are deleted after the retention window and are never used for training.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/video/gif \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"audio":"https://ejemplo.com/audio.mp3"}'const res = await fetch("https://api.kit.forhosting.com/video/gif", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"audio": "https://ejemplo.com/audio.mp3"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/video/gif",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"audio": "https://ejemplo.com/audio.mp3"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/video/gif", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"audio":"https://ejemplo.com/audio.mp3"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"audio":"https://ejemplo.com/audio.mp3"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/video/gif", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"audio": "https://ejemplo.com/audio.mp3"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "video.gif",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 500 |
max_minutes | 60 |
max_megapixels | 3.9 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |