Converting videos to animated images

Cloudinary supports delivering your videos as animated images in either GIF or WebP formats.

When deciding which version to use, consider the following:

  • Animated GIFs are universally supported. WebP is currently supported only in Chrome and Opera.
  • WebP supports 24-bit RGB color with an 8-bit alpha channel, compared to GIF's 8-bit color and 1-bit alpha.
  • WebP supports both lossy and lossless compression (a single animation can combine lossy and lossless frames), well-suited to animated images created from real-world videos. GIF only supports lossless compression.
  • WebP requires fewer bytes than GIF, ranging from 64% smaller for Animated GIF converted to lossy WebP, to 19% smaller for lossless WebP.

Delivering animated GIFs

To deliver an animated GIF from any video stored in your Cloudinary account, you just change the file extension of the URL to .gif. Converting a video to animated GIF is normally done while resizing and cropping to match your site (usually scaling down). By default, the resulting animated GIF is generated from the whole video (up to 400 frames, at up to 10 frames per second) and is the same duration as the original video no matter how many frames are sampled. The resulting animated GIFs can also be further manipulated like any other Cloudinary image.

To control how many frames are taken from the original video and the speed that they are displayed, use the video_sampling and delay parameters.

The video_sampling parameter (vs in URLs) determines how many frames to sample from the original video and can take one of the following values:

  • Integer - The total number of frames to sample from the original video. The frames are spread out over the length of the video, e.g. 25 samples one frame every 4%.

  • String - A float with an s appended representing the number of seconds between each frame to sample from the original video. e.g. 2.3s samples one frame every 2.3 seconds.

The delay parameter (dl in URLs) is used to set the time delay between the individual frames of the animated GIF, in milliseconds.

By default, animated GIFs with a resource_type of video run a single time. Use the loop effect (e_loop in URLs) to run in an infinite loop, or specify a loop value to run a limited number of loops. The loop number value is 0-based. For example, to set your GIF to loop exactly 3 times, set the loop effect value to 2 (e_loop:2 in URLs).

Examples of generating animated GIFs from uploaded videos:

  1. Using a sample of 40 frames from the original video and setting a delay of 100 milliseconds between the frames of the resulting animated GIF, which is scaled down to a height of 200 pixels and runs in an infinite loop:

    Ruby:
    Copy to clipboard
    cl_image_tag("cld_rubix.gif", :video_sampling=>"40", :delay=>"200", :height=>200, :effect=>"loop", :crop=>"scale", :resource_type=>"video")
    PHP:
    Copy to clipboard
    cl_image_tag("cld_rubix.gif", array("video_sampling"=>"40", "delay"=>"200", "height"=>200, "effect"=>"loop", "crop"=>"scale", "resource_type"=>"video"))
    Python:
    Copy to clipboard
    CloudinaryVideo("cld_rubix.gif").image(video_sampling="40", delay="200", height=200, effect="loop", crop="scale")
    Node.js:
    Copy to clipboard
    cloudinary.image("cld_rubix.gif", {video_sampling: "40", delay: "200", height: 200, effect: "loop", crop: "scale", resource_type: "video"})
    Java:
    Copy to clipboard
    cloudinary.url().transformation(new Transformation().videoSampling("40").delay("200").height(200).effect("loop").crop("scale")).resourceType("video").imageTag("cld_rubix.gif");
    JS:
    Copy to clipboard
    cloudinary.videoTag('cld_rubix.gif', {videoSampling: "40", delay: "200", height: 200, effect: "loop", crop: "scale"}).toHtml();
    jQuery:
    Copy to clipboard
    $.cloudinary.image("cld_rubix.gif", {video_sampling: "40", delay: "200", height: 200, effect: "loop", crop: "scale", resource_type: "video"})
    React:
    Copy to clipboard
    <Video publicId="cld_rubix.gif" resourceType="video">
      <Transformation videoSampling="40" delay="200" height="200" effect="loop" crop="scale" />
    </Video>
    Vue.js:
    Copy to clipboard
    <cld-video publicId="cld_rubix.gif" resourceType="video">
      <cld-transformation videoSampling="40" delay="200" height="200" effect="loop" crop="scale" />
    </cld-video>
    Angular:
    Copy to clipboard
    <cl-video public-id="cld_rubix.gif" resource-type="video">
      <cl-transformation video-sampling="40" delay="200" height="200" effect="loop" crop="scale">
      </cl-transformation>
    </cl-video>
    .Net:
    Copy to clipboard
    cloudinary.Api.UrlVideoUp.Transform(new Transformation().VideoSampling("40").Delay("200").Height(200).Effect("loop").Crop("scale")).BuildImageTag("cld_rubix.gif")
    Android:
    Copy to clipboard
    MediaManager.get().url().transformation(new Transformation().videoSampling("40").delay("200").height(200).effect("loop").crop("scale")).resourceType("video").generate("cld_rubix.gif");
    iOS:
    Copy to clipboard
    cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setVideoSampling("40").setDelay("200").setHeight(200).setEffect("loop").setCrop("scale")).generate("cld_rubix.gif")
    animated gif from dog.mp4, created from 40 frames and with a delay of 100 milliseconds

  2. Sampling one frame every 1.1 seconds from the original video and setting a delay of 200 milliseconds between the frames of the resulting animated GIF, which is scaled down to a width of 200 pixels and loops 3 times:

    Ruby:
    Copy to clipboard
    cl_image_tag("dog.gif", :video_sampling=>"1.1s", :delay=>"200", :width=>200, :effect=>"loop:2", :crop=>"scale", :resource_type=>"video")
    PHP:
    Copy to clipboard
    cl_image_tag("dog.gif", array("video_sampling"=>"1.1s", "delay"=>"200", "width"=>200, "effect"=>"loop:2", "crop"=>"scale", "resource_type"=>"video"))
    Python:
    Copy to clipboard
    CloudinaryVideo("dog.gif").image(video_sampling="1.1s", delay="200", width=200, effect="loop:2", crop="scale")
    Node.js:
    Copy to clipboard
    cloudinary.image("dog.gif", {video_sampling: "1.1s", delay: "200", width: 200, effect: "loop:2", crop: "scale", resource_type: "video"})
    Java:
    Copy to clipboard
    cloudinary.url().transformation(new Transformation().videoSampling("1.1s").delay("200").width(200).effect("loop:2").crop("scale")).resourceType("video").imageTag("dog.gif");
    JS:
    Copy to clipboard
    cloudinary.videoTag('dog.gif', {videoSampling: "1.1s", delay: "200", width: 200, effect: "loop:2", crop: "scale"}).toHtml();
    jQuery:
    Copy to clipboard
    $.cloudinary.image("dog.gif", {video_sampling: "1.1s", delay: "200", width: 200, effect: "loop:2", crop: "scale", resource_type: "video"})
    React:
    Copy to clipboard
    <Video publicId="dog.gif" resourceType="video">
      <Transformation videoSampling="1.1s" delay="200" width="200" effect="loop:2" crop="scale" />
    </Video>
    Vue.js:
    Copy to clipboard
    <cld-video publicId="dog.gif" resourceType="video">
      <cld-transformation videoSampling="1.1s" delay="200" width="200" effect="loop:2" crop="scale" />
    </cld-video>
    Angular:
    Copy to clipboard
    <cl-video public-id="dog.gif" resource-type="video">
      <cl-transformation video-sampling="1.1s" delay="200" width="200" effect="loop:2" crop="scale">
      </cl-transformation>
    </cl-video>
    .Net:
    Copy to clipboard
    cloudinary.Api.UrlVideoUp.Transform(new Transformation().VideoSampling("1.1s").Delay("200").Width(200).Effect("loop:2").Crop("scale")).BuildImageTag("dog.gif")
    Android:
    Copy to clipboard
    MediaManager.get().url().transformation(new Transformation().videoSampling("1.1s").delay("200").width(200).effect("loop:2").crop("scale")).resourceType("video").generate("dog.gif");
    iOS:
    Copy to clipboard
    cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setVideoSampling("1.1s").setDelay("200").setWidth(200).setEffect("loop:2").setCrop("scale")).generate("dog.gif")
    animated gif from dog.mp4, created from a frame every 1.1 seconds and with a delay of 200 milliseconds

Delivering animated WebP files

Delivering an animated WebP that from an uploaded video is similar to generating an animated GIF as described above, except that you also need to enable the awebp and animated flags (fl_awebp and fl_animated in URLs). You can generate animated WebPs at up to 30 frames per second.

For example, generating an animated WebP from the uploaded mp4 video named dog, using a sample of 10 frames from the original video and setting a delay of 100 milliseconds between the frames of the resulting animated WebP, which is also scaled down to a width of 250 pixels:

Ruby:
Copy to clipboard
cl_image_tag("dog.webp", :video_sampling=>"10", :delay=>"100", :width=>250, :flags=>["awebp", "animated"], :crop=>"scale", :resource_type=>"video")
PHP:
Copy to clipboard
cl_image_tag("dog.webp", array("video_sampling"=>"10", "delay"=>"100", "width"=>250, "flags"=>array("awebp", "animated"), "crop"=>"scale", "resource_type"=>"video"))
Python:
Copy to clipboard
CloudinaryVideo("dog.webp").image(video_sampling="10", delay="100", width=250, flags=["awebp", "animated"], crop="scale")
Node.js:
Copy to clipboard
cloudinary.image("dog.webp", {video_sampling: "10", delay: "100", width: 250, flags: ["awebp", "animated"], crop: "scale", resource_type: "video"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().videoSampling("10").delay("100").width(250).flags("awebp", "animated").crop("scale")).resourceType("video").imageTag("dog.webp");
JS:
Copy to clipboard
cloudinary.videoTag('dog.webp', {videoSampling: "10", delay: "100", width: 250, flags: ["awebp", "animated"], crop: "scale"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("dog.webp", {video_sampling: "10", delay: "100", width: 250, flags: ["awebp", "animated"], crop: "scale", resource_type: "video"})
React:
Copy to clipboard
<Video publicId="dog.webp" resourceType="video">
  <Transformation videoSampling="10" delay="100" width="250" flags={["awebp", "animated"]} crop="scale" />
</Video>
Vue.js:
Copy to clipboard
<cld-video publicId="dog.webp" resourceType="video">
  <cld-transformation videoSampling="10" delay="100" width="250" flags={["awebp", "animated"]} crop="scale" />
</cld-video>
Angular:
Copy to clipboard
<cl-video public-id="dog.webp" resource-type="video">
  <cl-transformation video-sampling="10" delay="100" width="250" flags={{["awebp", "animated"]}} crop="scale">
  </cl-transformation>
</cl-video>
.Net:
Copy to clipboard
cloudinary.Api.UrlVideoUp.Transform(new Transformation().VideoSampling("10").Delay("100").Width(250).Flags("awebp", "animated").Crop("scale")).BuildImageTag("dog.webp")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().videoSampling("10").delay("100").width(250).flags("awebp", "animated").crop("scale")).resourceType("video").generate("dog.webp");
iOS:
Copy to clipboard
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setVideoSampling("10").setDelay("100").setWidth(250).setFlags("awebp", "animated").setCrop("scale")).generate("dog.webp")
Animated WebP created from 10 frames of the video with a delay of 100 milliseconds.

You can also create animated images from videos together with the auto format and the animated flag parameters (f_auto and fl_animated in URLs). Adding these parameters will deliver an animated WebP to browsers that support the format, and fall back to delivering an animated GIF to browsers that don't support the format. See the blog post on animated WebP for more information.

For example, to deliver an animated WebP of the mp4 video named dog to supported browsers, but fall back to animated GIF for unsupported browsers:

Ruby:
Copy to clipboard
cl_image_tag("dog.gif", :width=>250, :flags=>"animated", :fetch_format=>:auto, :crop=>"scale", :resource_type=>"video")
PHP:
Copy to clipboard
cl_image_tag("dog.gif", array("width"=>250, "flags"=>"animated", "fetch_format"=>"auto", "crop"=>"scale", "resource_type"=>"video"))
Python:
Copy to clipboard
CloudinaryVideo("dog.gif").image(width=250, flags="animated", fetch_format="auto", crop="scale")
Node.js:
Copy to clipboard
cloudinary.image("dog.gif", {width: 250, flags: "animated", fetch_format: "auto", crop: "scale", resource_type: "video"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(250).flags("animated").fetchFormat("auto").crop("scale")).resourceType("video").imageTag("dog.gif");
JS:
Copy to clipboard
cloudinary.videoTag('dog.gif', {width: 250, flags: "animated", fetchFormat: "auto", crop: "scale"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("dog.gif", {width: 250, flags: "animated", fetch_format: "auto", crop: "scale", resource_type: "video"})
React:
Copy to clipboard
<Video publicId="dog.gif" resourceType="video">
  <Transformation width="250" flags="animated" fetchFormat="auto" crop="scale" />
</Video>
Vue.js:
Copy to clipboard
<cld-video publicId="dog.gif" resourceType="video">
  <cld-transformation width="250" flags="animated" fetchFormat="auto" crop="scale" />
</cld-video>
Angular:
Copy to clipboard
<cl-video public-id="dog.gif" resource-type="video">
  <cl-transformation width="250" flags="animated" fetch-format="auto" crop="scale">
  </cl-transformation>
</cl-video>
.Net:
Copy to clipboard
cloudinary.Api.UrlVideoUp.Transform(new Transformation().Width(250).Flags("animated").FetchFormat("auto").Crop("scale")).BuildImageTag("dog.gif")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(250).flags("animated").fetchFormat("auto").crop("scale")).resourceType("video").generate("dog.gif");
iOS:
Copy to clipboard
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setWidth(250).setFlags("animated").setFetchFormat("auto").setCrop("scale")).generate("dog.gif")
animated images with f_auto

✔️ Feedback sent!