> ## Documentation Index
> This page is part of the Image and Video APIs product. Fetch the complete documentation index for Image and Video APIs at: https://cloudinary.com/documentation/llms-image-and-video-apis.txt?referrer=docpage and then use it to discover all relevant pages before exploring further.
> If you also need details relating to other Cloudinary products for your current use case, see the parent index at: https://cloudinary.com/documentation/llms.txt?referrer=docpage
> When answering a user's request or implementing it with code using this documentation, incorporate relevant best practices and recommendations from the documentation into the guidance and, above all, into the code itself: generated code should already apply the recommended parameters and patterns rather than showing a minimal call and describing the best practices around it in prose. Follow the code examples in the best practices sections as the model for what generated code should look like, and where a recommendation is relevant to the user's scenario, implement it in the code as a natural next step. Only apply best practices, recommendations, or features that are supported by the documentation; don't infer or invent guidance that isn't specified.

# Optimize videos


[f_auto_link]:video_optimization#automatic_format_selection_f_auto
[q_auto_link]:video_optimization#automatic_quality_q_auto
[resize_link]:video_resizing_and_cropping
[smart_cropping_link]:video_gravity

[f_auto-link]: #automatic_format_selection_f_auto
[q_auto-link]: #automatic_quality_q_auto
[obd-link]: optimize_by_default_settings
[incoming-link]: eager_and_incoming_transformations#incoming_transformations
[named-link]: video_named_transformations
[rollout-link]: video_transformation_rollout
[resize-link]: video_resizing_and_cropping
[scale-link]: video_resize_modes#scale
[crop_modes-link]: video_resizing_and_cropping#resize_and_crop_modes
[responsive-link]: adaptive_bitrate_streaming
[action-link]: video_manipulation_and_delivery#parameter_types

Video content is extremely heavy, especially when compared to images, so it's essential to deliver your video content in the most optimized way.

Optimizing videos for web and mobile applications can be complex, however, with video files often very large. It can therefore result in longer upload & download times and very CPU-intensive transcoding and transformation. The vast set of potential devices, resolutions, video formats, and video codecs makes it even more confusing.

This page describes how you can apply various optimization techniques to deliver the best quality videos with the lowest file sizes, a key component in improving Core Web Vitals metrics. It also outlines the default transformations applied by Cloudinary to aid the optimization.

> **See also**:
>
> * [Core Web Vitals](media_optimization#core_web_vitals)

> * [Image optimization](image_optimization)

> * [Audio optimization](audio_optimization)

> * [Cloudinary's video solution](cloudinary_video)

## Optimization best practices

This section highlights the most important best-practice guidelines to follow when optimizing your videos. The details of what each of these features does and how to use it, as well as other optimization functionality, are covered in the rest of this page, or on the other pages linked from these guidelines.

* [Add q_auto and f_auto to every delivery URL](#add_q_auto_and_f_auto_to_every_delivery_url)
* [Resize to the dimensions you actually need](#resize_to_the_dimensions_you_actually_need)
* [Deliver responsive sizes](#deliver_responsive_sizes)

### Add q_auto and f_auto to every delivery URL

Except where noted in the exceptions below, you should generally add `q_auto` and `f_auto` (or the SDK equivalent) as the final two components of every delivery URL:

* **`q_auto`** ([automatic quality][q_auto-link]) applies the best balance of visual quality and file size.
* **`f_auto`** ([automatic format selection][f_auto-link]) delivers each video in the optimal format for the requesting browser.

Together they reduce bandwidth and improve performance with a single, small addition to your URL.

> **TIP**: The order of these two parameters doesn't matter (`q_auto/f_auto` or `f_auto/q_auto`), but as with any transformation [action][action-link] parameter, they should be specified as separate components. In a delivery URL, that means separating them with a slash (`/`), not a comma.

#### Automatic quality and format example
The original MP4 below is 3.7 MB. Just adding `q_auto` and `f_auto` brings the delivered file down to about 0.55 MB (around 85% smaller). `q_auto` keeps the visual quality nearly identical despite the significantly smaller file size, while `f_auto` causes most browsers to receive it as WebM (VP9) rather than the original MP4.

![Image optimized with q_auto/f_auto](https://res.cloudinary.com/demo/image/upload/q_auto/f_auto/docs/shoes.jpg "thumb: w_400,dpr_2, width:400")

```nodejs
cloudinary.image("docs/shoes.jpg", {transformation: [
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/shoes.jpg")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```vue
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/shoes.jpg")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```angular
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/shoes.jpg")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```js
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/shoes.jpg")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```python
CloudinaryImage("docs/shoes.jpg").image(transformation=[
  {'quality': "auto"},
  {'fetch_format': "auto"}
  ])
```

```php
use Cloudinary\Transformation\Delivery;
use Cloudinary\Transformation\Quality;
use Cloudinary\Transformation\Format;

(new ImageTag('docs/shoes.jpg'))
	->delivery(Delivery::quality(
	Quality::auto()))
	->delivery(Delivery::format(
	Format::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .quality("auto").chain()
  .fetchFormat("auto")).imageTag("docs/shoes.jpg");
```

```ruby
cl_image_tag("docs/shoes.jpg", transformation: [
  {quality: "auto"},
  {fetch_format: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Quality("auto").Chain()
  .FetchFormat("auto")).BuildImageTag("docs/shoes.jpg")
```

```dart
cloudinary.image('docs/shoes.jpg').transformation(Transformation()
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setQuality("auto").chain()
  .setFetchFormat("auto")).generate("docs/shoes.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .quality("auto").chain()
  .fetchFormat("auto")).generate("docs/shoes.jpg");
```

```flutter
cloudinary.image('docs/shoes.jpg').transformation(Transformation()
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```kotlin
cloudinary.image {
	publicId("docs/shoes.jpg")
	 delivery(Delivery.quality(
	Quality.auto()))
	 delivery(Delivery.format(
	Format.auto())) 
}.generate()
```

```jquery
$.cloudinary.image("docs/shoes.jpg", {transformation: [
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react_native
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/shoes.jpg")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

![Video optimized with q_auto/f_auto](https://res.cloudinary.com/demo/video/upload/q_auto/f_auto/guy_woman_mobile.mp4 "thumb: w_400,dpr_2, width:400")

```nodejs
cloudinary.video("guy_woman_mobile", {transformation: [
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("guy_woman_mobile.mp4")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```vue
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("guy_woman_mobile.mp4")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```angular
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("guy_woman_mobile.mp4")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```js
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("guy_woman_mobile.mp4")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```python
CloudinaryVideo("guy_woman_mobile").video(transformation=[
  {'quality': "auto"},
  {'fetch_format': "auto"}
  ])
```

```php
use Cloudinary\Transformation\Delivery;
use Cloudinary\Transformation\Quality;
use Cloudinary\Transformation\Format;

(new VideoTag('guy_woman_mobile.mp4'))
	->delivery(Delivery::quality(
	Quality::auto()))
	->delivery(Delivery::format(
	Format::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .quality("auto").chain()
  .fetchFormat("auto")).videoTag("guy_woman_mobile");
```

```ruby
cl_video_tag("guy_woman_mobile", transformation: [
  {quality: "auto"},
  {fetch_format: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Quality("auto").Chain()
  .FetchFormat("auto")).BuildVideoTag("guy_woman_mobile")
```

```dart
cloudinary.video('guy_woman_mobile.mp4').transformation(Transformation()
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setQuality("auto").chain()
  .setFetchFormat("auto")).generate("guy_woman_mobile.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .quality("auto").chain()
  .fetchFormat("auto")).resourceType("video").generate("guy_woman_mobile.mp4");
```

```flutter
cloudinary.video('guy_woman_mobile.mp4').transformation(Transformation()
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```kotlin
cloudinary.video {
	publicId("guy_woman_mobile.mp4")
	 delivery(Delivery.quality(
	Quality.auto()))
	 delivery(Delivery.format(
	Format.auto())) 
}.generate()
```

```jquery
$.cloudinary.video("guy_woman_mobile", {transformation: [
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react_native
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("guy_woman_mobile.mp4")
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

> **NOTE**:
>
> :title=Exceptions
> Don't add `q_auto`/`f_auto` when:

> * Your account has [Optimize by default][obd-link] enabled (Enterprise only), which already applies both settings automatically.

> * You intentionally want to deliver a lower or higher quality than `q_auto` would select. In that case, use an option like `q_auto:best` or `q_auto:low`, which still applies smart quality delivery but is tuned to be more or less aggressive than the default. In rare cases, you can specify a manual `q_<n>` value instead. See all available [q_auto options](#automatic_quality_q_auto) below.

> * There's a specific requirement to deliver a predefined format. In that case, replace `f_auto` with `f_png`, `f_jpg`, etc.

> * There's a specific requirement to deliver the exact original with no modifications (for example, a photographer app displays watermarked versions of images and videos, but enables customers download full-quality, non-optimized originals after purchasing them).

Never use `f_auto` (or the combined `q_auto`/`f_auto`) in an [incoming transformation][incoming-link] or a [named transformation][named-link]. Format selection has to be resolved per request at the CDN during delivery, based on the requesting browser. That can't happen when `f_auto` is requested as part of an upload (an incoming transformation), or when the `f_auto` instruction is stored inside a named transformation definition. 

If you're using named transformations, you can keep all other transformations in the named transformation and then chain the `f_auto` after it. For example, `t_square/f_auto`. For the full workflow, including how to warm the cache with matching eager transformations, see the [transformation rollout guide][rollout-link].

### Resize to the dimensions you actually need

Use [resizing transformations][resize-link] so your video is delivered no larger than the maximum dimensions and resolution your use case requires. Avoid relying on client-side or CSS resizing whenever possible, since it downloads more data than needed.

* Use the [`c_scale`][scale-link] crop mode if you just want to resize for optimization purposes without other changes.
* Choose [another crop mode][crop_modes-link] if it better fits your use case.

#### Resize example

For example, the original video below is 1920 x 1080 px, but it's delivered at 500 x 281 px. The resize happens on Cloudinary's servers before delivery, so even setting aside the `q_auto` and `f_auto` that are also applied here, delivering the smaller resized video instead of the full-resolution original is a significant optimization on its own.

![Image resized with c_scale](https://res.cloudinary.com/demo/image/upload/c_scale,w_500/q_auto/f_auto/docs/camera.jpg "thumb: w_500,dpr_2, width:500")

```nodejs
cloudinary.image("docs/camera.jpg", {transformation: [
  {width: 500, crop: "scale"},
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/camera.jpg")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```vue
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/camera.jpg")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```angular
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/camera.jpg")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```js
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/camera.jpg")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```python
CloudinaryImage("docs/camera.jpg").image(transformation=[
  {'width': 500, 'crop': "scale"},
  {'quality': "auto"},
  {'fetch_format': "auto"}
  ])
```

```php
use Cloudinary\Transformation\Resize;
use Cloudinary\Transformation\Delivery;
use Cloudinary\Transformation\Quality;
use Cloudinary\Transformation\Format;

(new ImageTag('docs/camera.jpg'))
	->resize(Resize::scale()->width(500))
	->delivery(Delivery::quality(
	Quality::auto()))
	->delivery(Delivery::format(
	Format::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .width(500).crop("scale").chain()
  .quality("auto").chain()
  .fetchFormat("auto")).imageTag("docs/camera.jpg");
```

```ruby
cl_image_tag("docs/camera.jpg", transformation: [
  {width: 500, crop: "scale"},
  {quality: "auto"},
  {fetch_format: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Width(500).Crop("scale").Chain()
  .Quality("auto").Chain()
  .FetchFormat("auto")).BuildImageTag("docs/camera.jpg")
```

```dart
cloudinary.image('docs/camera.jpg').transformation(Transformation()
	.resize(Resize.scale().width(500))
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setWidth(500).setCrop("scale").chain()
  .setQuality("auto").chain()
  .setFetchFormat("auto")).generate("docs/camera.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .width(500).crop("scale").chain()
  .quality("auto").chain()
  .fetchFormat("auto")).generate("docs/camera.jpg");
```

```flutter
cloudinary.image('docs/camera.jpg').transformation(Transformation()
	.resize(Resize.scale().width(500))
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```kotlin
cloudinary.image {
	publicId("docs/camera.jpg")
	 resize(Resize.scale() { width(500) })
	 delivery(Delivery.quality(
	Quality.auto()))
	 delivery(Delivery.format(
	Format.auto())) 
}.generate()
```

```jquery
$.cloudinary.image("docs/camera.jpg", {transformation: [
  {width: 500, crop: "scale"},
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react_native
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage("docs/camera.jpg")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

![Video resized with c_scale](https://res.cloudinary.com/demo/video/upload/c_scale,w_500/q_auto/f_auto/paradise_location.mp4 "thumb: w_500,dpr_2, width:500")

```nodejs
cloudinary.video("paradise_location", {transformation: [
  {width: 500, crop: "scale"},
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("paradise_location.mp4")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```vue
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("paradise_location.mp4")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```angular
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("paradise_location.mp4")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```js
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("paradise_location.mp4")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

```python
CloudinaryVideo("paradise_location").video(transformation=[
  {'width': 500, 'crop': "scale"},
  {'quality': "auto"},
  {'fetch_format': "auto"}
  ])
```

```php
use Cloudinary\Transformation\Resize;
use Cloudinary\Transformation\Delivery;
use Cloudinary\Transformation\Quality;
use Cloudinary\Transformation\Format;

(new VideoTag('paradise_location.mp4'))
	->resize(Resize::scale()->width(500))
	->delivery(Delivery::quality(
	Quality::auto()))
	->delivery(Delivery::format(
	Format::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .width(500).crop("scale").chain()
  .quality("auto").chain()
  .fetchFormat("auto")).videoTag("paradise_location");
```

```ruby
cl_video_tag("paradise_location", transformation: [
  {width: 500, crop: "scale"},
  {quality: "auto"},
  {fetch_format: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Width(500).Crop("scale").Chain()
  .Quality("auto").Chain()
  .FetchFormat("auto")).BuildVideoTag("paradise_location")
```

```dart
cloudinary.video('paradise_location.mp4').transformation(Transformation()
	.resize(Resize.scale().width(500))
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setWidth(500).setCrop("scale").chain()
  .setQuality("auto").chain()
  .setFetchFormat("auto")).generate("paradise_location.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .width(500).crop("scale").chain()
  .quality("auto").chain()
  .fetchFormat("auto")).resourceType("video").generate("paradise_location.mp4");
```

```flutter
cloudinary.video('paradise_location.mp4').transformation(Transformation()
	.resize(Resize.scale().width(500))
	.delivery(Delivery.quality(
	Quality.auto()))
	.delivery(Delivery.format(
	Format.auto())));
```

```kotlin
cloudinary.video {
	publicId("paradise_location.mp4")
	 resize(Resize.scale() { width(500) })
	 delivery(Delivery.quality(
	Quality.auto()))
	 delivery(Delivery.format(
	Format.auto())) 
}.generate()
```

```jquery
$.cloudinary.video("paradise_location", {transformation: [
  {width: 500, crop: "scale"},
  {quality: "auto"},
  {fetch_format: "auto"}
  ]})
```

```react_native
import { scale } from "@cloudinary/url-gen/actions/resize";
import { quality, format } from "@cloudinary/url-gen/actions/delivery";
import { auto as autoQuality } from "@cloudinary/url-gen/qualifiers/quality";
import { auto as autoFormat } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("paradise_location.mp4")
  .resize(scale().width(500))
  .delivery(quality(autoQuality()))
  .delivery(format(autoFormat()));
```

### Deliver responsive sizes

Use [responsive delivery features][responsive-link] to serve the right sizes to various desktop and mobile devices across different screen widths depending on the viewport.

For videos, responsive delivery is handled mainly through [adaptive bitrate streaming](adaptive_bitrate_streaming), which automatically adjusts the resolution and bitrate to each viewer's bandwidth and screen. You can also [resize](video_resizing_and_cropping) to deliver a version sized for the target layout.

## Default optimizations

Cloudinary performs default optimizations when delivering media assets. You can control these for your product environment in [Optimization Settings](https://console.cloudinary.com/app/settings/optimization) and override them through transformation parameters.

Certain plans include the ability to optimize the video format by default (see [Optimize by default](optimize_by_default_settings)). All plans let you optimize [video quality](#default_video_quality) by default.

> **NOTE**:
>
> The default optimizations affect only the **delivered** video. The original video file remains unchanged.

### Default video quality

The **Default video quality** setting is applied to all videos delivered from your product environment, together with an automatically determined video codec ([vc_auto](transformation_reference#vc_auto)), but only if other transformations are also applied.

![Default video quality setting](https://cloudinary-res.cloudinary.com/image/upload/bo_1px_solid_gray/q_auto/f_auto/v1683798132/docs/optimization/default_video_quality.png "thumb: c_scale,w_600,dpr_2.0, width: 600")

This applies a certain amount of compression to your videos in order to reduce the weight of the video.

We recommend choosing an [automatic quality setting](#automatic_quality_q_auto) to apply to all your transformed videos rather than a [specific quality level](#set_the_quality_when_delivering_a_video). 

To override the default settings, set the [quality parameter](transformation_reference#q_quality) in your transformation (`q_` in URLs).

### Metadata stripping

When you deliver a video from Cloudinary with any transformation applied, Cloudinary strips the global metadata from the derived video, in the same way as it does for [images](image_optimization#metadata_stripping). Global metadata is the descriptive information embedded in the file, such as title, artist, album, description, copyright, GPS location, and chapter markers. The properties of the video and audio streams themselves aren't affected.

Cloudinary is gradually rolling out this behavior. It applies to all product environments created on or after June 21, 2026, and Cloudinary is enabling it for product environments created before that date over time. During the rollout, derived videos in your product environment may still keep the metadata of the original video.

To override this behavior and keep the metadata in the derived video, add the [fl_keep_iptc flag](transformation_reference#fl_keep_iptc).

> **NOTES**:
>
> * Chapter markers are always stripped, and the fields that are retained depend on the output format. Metadata stored in other ways, such as Adobe XMP or Apple QuickTime keys, isn't preserved. For the full list of limitations, see [fl_keep_iptc](transformation_reference#fl_keep_iptc).

> * [Incoming transformations](eager_and_incoming_transformations#incoming_transformations) keep the metadata of the original video. Add the [fl_force_strip flag](transformation_reference#fl_force_strip) to strip it at upload.

> * [Adaptive bitrate streaming](adaptive_bitrate_streaming) outputs always have their metadata stripped, and `fl_keep_iptc` isn't supported for them.

> * Animated outputs (GIF, and animated WebP, PNG, and AVIF) can't carry this metadata, so it's always dropped.

> * The [fl_keep_attribution](transformation_reference#fl_keep_attribution) flag isn't supported for videos. Use `fl_keep_iptc` instead.

## How to optimize video quality

The video quality setting defines the compression level to apply to a video. 

The setting you choose entails a trade-off between visual quality and file size: the lower the quality value, the more the file is compressed to a smaller file size, and the more data is lost in the process, the result of which is a loss of visual quality. At the higher quality levels, the loss of visual quality is barely noticeable to the human eye. The ultimate visual quality result also depends on other factors such as the size of the original video and the resolution of the user's monitor or mobile screen.

Adjusting the quality of your videos to a level that still provides good visual output, is one of the most powerful tools in video optimization. You can often deliver videos at less than half of the original file size with little to no visually noticeable difference. Optimizing video quality can also help improve your [Core Web Vitals](media_optimization#core_web_vitals) score.

There are a few ways to control the quality of videos delivered from Cloudinary: 

* [Set the default quality for your product environment](#default_video_quality)
* [Use automatic quality selection (q_auto)](#automatic_quality_q_auto)
* [Set the quality when delivering a video](#set_the_quality_when_delivering_a_video)
* [Control the quality of WEBM transcoding](#control_the_quality_of_webm_transcoding)
* [Use bitrate control](#bitrate_control)
* [Use adaptive bitrate streaming](#adaptive_bitrate_streaming)

### Automatic quality (q_auto)

Instead of defining a specific quality value, you can use Cloudinary's intelligent quality and encoding algorithm. The algorithm analyzes each video to decide on the optimal encoding characteristics that will produce the best visual quality while minimizing the file size.

The quality transformation parameter can be set to auto (`q_auto` in URLs) in order to perform automatic quality encoding. Further control of the automatic quality selection is supported as follows:

* `q_auto` - The optimal balance between file size and visual quality. By default, this is the same as q_auto:good.
* `q_auto:best` - Less aggressive algorithm. Generates bigger files with potentially better visual quality.
* `q_auto:good` - Ensuring a relatively small file size with good visual quality. Example of a target audience: stock media sites that display videos with a high visual quality.
* `q_auto:eco` - More aggressive algorithm, which results in smaller files of slightly lower visual quality. Example of a target audience: popular sites and social networks with a huge amount of traffic.
* `q_auto:low` - Most aggressive algorithm, which results in the smallest files of low visual quality. Example of a target audience: sites using thumbnail preview videos that then link to higher quality videos.

#### Save-Data support
Save-Data support is a feature included in the [Client-Hints](https://developer.mozilla.org/en-US/docs/Glossary/Client_hints) standard, which is already supported by Chrome and Opera browsers. The browsers send a special request header named `Save-Data` if the user has enabled data saving mode. When `q_auto` is specified and the `Save-Data: on` header reaches the CDN layer of Cloudinary, image compression and encoding will automatically switch to the `eco` mode (`q_auto:eco`) instead of the default `good` quality mode (`q_auto:good`). This feature has implications for using `q_auto` in [named transformations](video_named_transformations#automatic_quality_in_named_transformations).

#### Interactive demo: automatic video quality
Click the various quality settings below to see how the resulting file size is affected when encoding the hourglass video:

 

 https://res.cloudinary.com/demo/video/upload/w_600/q_auto:low/hourglass_timer.mp4

 Quality: 
<code> auto:low

 Size: 
 <code>170.27KB

 auto:low
 auto:eco            
 auto:good
 auto:best
 80
 100

 

> **NOTES**:
>
> * Automatic quality is supported for videos using the `h264`, `h265` and `VP9` codecs. 

> * Cloudinary already performs some basic content-aware encoding when delivering a transformed video. See [vc (video\_codec)](transformation_reference#vc_video_codec) in the _Transformation URL API Reference_ for the default settings for each format, which includes setting quality to 70. Using `q_auto` overrides this default setting, producing slightly different results depending on the complexity of the video.

**See also**: [q_auto for images](image_optimization#automatic_quality_selection_q_auto)

### Set the quality when delivering a video

You can control the video quality with the `quality` parameter (`q` in URLs). This parameter represents a mapping between the actual low-level settings of each different video format normalized to a quality value between 1 (lowest) and 100 (highest). Reducing the quality is a trade-off between visual quality and file size. See [vc (video\_codec)](transformation_reference#vc_video_codec) in the _Transformation URL API Reference_ for the default settings for each format.

For example, reducing the quality of the uploaded mp4 video named `jumping_from_rocks` to 50 results in a file size of **2.5 MB** compared to the original file size of **7.4 MB**:

![Video quality set to 50](https://res.cloudinary.com/demo/video/upload/q_50/docs/jumping_from_rocks.mp4 "thumb: w_500")

```nodejs
cloudinary.video("docs/jumping_from_rocks", {quality: 50})
```

```react
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("docs/jumping_from_rocks.mp4").delivery(quality(50));
```

```vue
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("docs/jumping_from_rocks.mp4").delivery(quality(50));
```

```angular
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("docs/jumping_from_rocks.mp4").delivery(quality(50));
```

```js
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("docs/jumping_from_rocks.mp4").delivery(quality(50));
```

```python
CloudinaryVideo("docs/jumping_from_rocks").video(quality=50)
```

```php
use Cloudinary\Transformation\Delivery;

(new VideoTag('docs/jumping_from_rocks.mp4'))
	->delivery(Delivery::quality(50));
```

```java
cloudinary.url().transformation(new Transformation().quality(50)).videoTag("docs/jumping_from_rocks");
```

```ruby
cl_video_tag("docs/jumping_from_rocks", quality: 50)
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation().Quality(50)).BuildVideoTag("docs/jumping_from_rocks")
```

```dart
cloudinary.video('docs/jumping_from_rocks.mp4').transformation(Transformation()
	.delivery(Delivery.quality(50)));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setQuality(50)).generate("docs/jumping_from_rocks.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation().quality(50)).resourceType("video").generate("docs/jumping_from_rocks.mp4");
```

```flutter
cloudinary.video('docs/jumping_from_rocks.mp4').transformation(Transformation()
	.delivery(Delivery.quality(50)));
```

```kotlin
cloudinary.video {
	publicId("docs/jumping_from_rocks.mp4")
	 delivery(Delivery.quality(50)) 
}.generate()
```

```jquery
$.cloudinary.video("docs/jumping_from_rocks", {quality: 50})
```

```react_native
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("docs/jumping_from_rocks.mp4").delivery(quality(50));
```

### Control the quality of WEBM transcoding

In some cases, transcoding videos from mp4 to webm (VP8/9 encoding) may give a pixelated result. In these cases, you can control the final quality by setting a maximum quantization percentage (1-100 range) value:`qmax` in addition to a fixed `quality` value. This can help ensure that the video is not over-quantized.

For example, you could set the `quality` parameter to: `"80:qmax_90"` to ensure that the transcoded video is quantized no more than 90% of the maximum possible quantization. When you set a `qmax` value, the quality value is relative to the quantization value.

For example, if you transcode the video below to .webm format without setting a max quantization value, the quality drops fairly significantly compared to its .mp4 counterpart, but by setting the max quantization to 70, you get a better visual quality.

![Using the max quantization parameter for improved webm streaming quality](https://res.cloudinary.com/demo/video/upload/du_30.0/q_70:qmax_20/Liverpool_vs_Roma_full.webm "with_image:false")

```nodejs
cloudinary.video("Liverpool_vs_Roma_full", {transformation: [
  {duration: "30.0"},
  {quality: "70:qmax_20"}
  ]})
```

```react
import { trim } from "@cloudinary/url-gen/actions/videoEdit";
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("Liverpool_vs_Roma_full.webm")
  .videoEdit(trim().duration("30.0"))
  .delivery(quality(70).quantization(20));
```

```vue
import { trim } from "@cloudinary/url-gen/actions/videoEdit";
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("Liverpool_vs_Roma_full.webm")
  .videoEdit(trim().duration("30.0"))
  .delivery(quality(70).quantization(20));
```

```angular
import { trim } from "@cloudinary/url-gen/actions/videoEdit";
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("Liverpool_vs_Roma_full.webm")
  .videoEdit(trim().duration("30.0"))
  .delivery(quality(70).quantization(20));
```

```js
import { trim } from "@cloudinary/url-gen/actions/videoEdit";
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("Liverpool_vs_Roma_full.webm")
  .videoEdit(trim().duration("30.0"))
  .delivery(quality(70).quantization(20));
```

```python
CloudinaryVideo("Liverpool_vs_Roma_full").video(transformation=[
  {'duration': "30.0"},
  {'quality': "70:qmax_20"}
  ])
```

```php
use Cloudinary\Transformation\VideoEdit;
use Cloudinary\Transformation\Delivery;

(new VideoTag('Liverpool_vs_Roma_full.webm'))
	->videoEdit(VideoEdit::trim()->duration(30.0))
	->delivery(Delivery::quality(70)->quantization(20));
```

```java
cloudinary.url().transformation(new Transformation()
  .duration("30.0").chain()
  .quality("70:qmax_20")).videoTag("Liverpool_vs_Roma_full");
```

```ruby
cl_video_tag("Liverpool_vs_Roma_full", transformation: [
  {duration: "30.0"},
  {quality: "70:qmax_20"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Duration("30.0").Chain()
  .Quality("70:qmax_20")).BuildVideoTag("Liverpool_vs_Roma_full")
```

```dart
cloudinary.video('Liverpool_vs_Roma_full.webm').transformation(Transformation()
	.videoEdit(VideoEdit.trim().duration('30.0'))
	.delivery(Delivery.quality(70).quantization(20)));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setDuration("30.0").chain()
  .setQuality("70:qmax_20")).generate("Liverpool_vs_Roma_full.webm")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .duration("30.0").chain()
  .quality("70:qmax_20")).resourceType("video").generate("Liverpool_vs_Roma_full.webm");
```

```flutter
cloudinary.video('Liverpool_vs_Roma_full.webm').transformation(Transformation()
	.videoEdit(VideoEdit.trim().duration('30.0'))
	.delivery(Delivery.quality(70).quantization(20)));
```

```kotlin
cloudinary.video {
	publicId("Liverpool_vs_Roma_full.webm")
	 videoEdit(VideoEdit.trim() { duration(30.0F) })
	 delivery(Delivery.quality(70) { quantization(20) }) 
}.generate()
```

```jquery
$.cloudinary.video("Liverpool_vs_Roma_full", {transformation: [
  {duration: "30.0"},
  {quality: "70:qmax_20"}
  ]})
```

```react_native
import { trim } from "@cloudinary/url-gen/actions/videoEdit";
import { quality } from "@cloudinary/url-gen/actions/delivery";

new CloudinaryVideo("Liverpool_vs_Roma_full.webm")
  .videoEdit(trim().duration("30.0"))
  .delivery(quality(70).quantization(20));
```

Keep in mind that the lower you set the `qmax` value, the higher the bitrate, and the larger the resulting file size.

If you don't supply a `qmax` value, then the **maximum** quantization is 100%, although the actual applied quantization will be determined by other factors such as the `quality` value you set (or your product environment's default quality setting), the content of the actual video, and other transformation and optimization options you include.

### Bitrate control

Use the `bit_rate` parameter (`br` in URLs) for advanced control of the bitrate for audio and video files. This parameter controls the number of bits used to represent the audio or video data. By default, the `br_` value uses variable bitrate (VBR), where the specified value indicates the maximum bitrate. The actual bitrate and quality are optimized according to the audio or video content, to conserve bandwidth and storage. You can also specify a constant bitrate value (CBR): `br_[value]:constant` in URLs. In this case, the specified bitrate will be used even in cases where that high of a rate is not necessary for good quality listening or viewing. When you specify a constant bitrate, the `quality` parameter is ignored.

`bit_rate` can take one of the following values:

* An integer e.g. `120000`.
* A string supporting 'k' and 'm' (kilobits and megabits respectively) e.g. `250k` or `2m`.

For example, setting the maximum bitrate of the uploaded mp4 video named `bathroom` to 250 kilobits (also reducing file size down to ~2.2 MB):

![bathroom.mp4 with 250k bit rate](https://res.cloudinary.com/demo/video/upload/br_250k/docs/bathroom.mp4 "thumb: w_500")

```nodejs
cloudinary.video("docs/bathroom", {bit_rate: "250k"})
```

```react
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/bathroom.mp4").transcode(bitRate("250k"));
```

```vue
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/bathroom.mp4").transcode(bitRate("250k"));
```

```angular
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/bathroom.mp4").transcode(bitRate("250k"));
```

```js
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/bathroom.mp4").transcode(bitRate("250k"));
```

```python
CloudinaryVideo("docs/bathroom").video(bit_rate="250k")
```

```php
use Cloudinary\Transformation\Transcode;

(new VideoTag('docs/bathroom.mp4'))
	->transcode(Transcode::bitRate("250k"));
```

```java
cloudinary.url().transformation(new Transformation().bitRate("250k")).videoTag("docs/bathroom");
```

```ruby
cl_video_tag("docs/bathroom", bit_rate: "250k")
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation().BitRate("250k")).BuildVideoTag("docs/bathroom")
```

```dart
cloudinary.video('docs/bathroom.mp4').transformation(Transformation()
	.transcode(Transcode.bitRate("250k")));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setBitRate("250k")).generate("docs/bathroom.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation().bitRate("250k")).resourceType("video").generate("docs/bathroom.mp4");
```

```flutter
cloudinary.video('docs/bathroom.mp4').transformation(Transformation()
	.transcode(Transcode.bitRate("250k")));
```

```kotlin
cloudinary.video {
	publicId("docs/bathroom.mp4")
	 transcode(Transcode.bitRate("250k")) 
}.generate()
```

```jquery
$.cloudinary.video("docs/bathroom", {bit_rate: "250k"})
```

```react_native
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/bathroom.mp4").transcode(bitRate("250k"));
```

> **NOTES**:
>
> * You can also control audio and video bitrate separately. See [br_av](transformation_reference#br_av) for full syntax. `br_av` is not currently supported by our SDKs.

> * If you define a maximum or constant bitrate as well as a [maximum quantization](#control_the_quality_of_webm_transcoding) (`qmax`), and there is a conflict between these two settings, the maximum or constant bitrate will take precedence.

### Meeting minimum bitrate thresholds

If your delivery pipeline requires videos to meet a minimum bitrate (for example, some streaming systems or ad platforms enforce bitrate floors), you can use constant bitrate (CBR) mode by appending `:constant` to the `bit_rate` value. With CBR, the encoder targets the specified bitrate throughout the video, even for scenes that could be efficiently compressed at a lower rate.

> **NOTE**: Strict CBR enforcement is supported only with the h264 video codec.

For example, to set a constant bitrate of 2500 kilobits per second:

![Video with constant bitrate of 2500k](https://res.cloudinary.com/demo/video/upload/br_2500k:constant/docs/parrot.mp4 "thumb: w_500")

```nodejs
cloudinary.video("docs/parrot", {bit_rate: "2500k:constant"})
```

```react
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/parrot.mp4").transcode(bitRate("2500k").constant());
```

```vue
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/parrot.mp4").transcode(bitRate("2500k").constant());
```

```angular
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/parrot.mp4").transcode(bitRate("2500k").constant());
```

```js
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/parrot.mp4").transcode(bitRate("2500k").constant());
```

```python
CloudinaryVideo("docs/parrot").video(bit_rate="2500k:constant")
```

```php
use Cloudinary\Transformation\Transcode;

(new VideoTag('docs/parrot.mp4'))
	->transcode(Transcode::bitRate("2500k")
	->constant()
	);
```

```java
cloudinary.url().transformation(new Transformation().bitRate("2500k:constant")).videoTag("docs/parrot");
```

```ruby
cl_video_tag("docs/parrot", bit_rate: "2500k:constant")
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation().BitRate("2500k:constant")).BuildVideoTag("docs/parrot")
```

```dart
cloudinary.video('docs/parrot.mp4').transformation(Transformation()
	.transcode(Transcode.bitRate("2500k")
	.constant()
	));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setBitRate("2500k:constant")).generate("docs/parrot.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation().bitRate("2500k:constant")).resourceType("video").generate("docs/parrot.mp4");
```

```flutter
cloudinary.video('docs/parrot.mp4').transformation(Transformation()
	.transcode(Transcode.bitRate("2500k")
	.constant()
	));
```

```kotlin
cloudinary.video {
	publicId("docs/parrot.mp4")
	 transcode(Transcode.bitRate("2500k") {
	 constant()
	 }) 
}.generate()
```

```jquery
$.cloudinary.video("docs/parrot", {bit_rate: "2500k:constant"})
```

```react_native
import { bitRate } from "@cloudinary/url-gen/actions/transcode";

new CloudinaryVideo("docs/parrot.mp4").transcode(bitRate("2500k").constant());
```

You can also control the video and audio bitrate independently using [br_av](transformation_reference#br_av). For example, to set a constant video bitrate of 2500k and an audio bitrate of 128k:

![Video with constant video bitrate of 2500k and audio bitrate of 128k](https://res.cloudinary.com/demo/video/upload/br_av:video_(value_2500k;mode_cbr)

```nodejs
cloudinary.image("br_av:video_(value_2500k;mode_cbr", {resource_type: "video"})
```

```react
new CloudinaryVideo("br_av:video_(value_2500k;mode_cbr");
```

```vue
new CloudinaryVideo("br_av:video_(value_2500k;mode_cbr");
```

```angular
new CloudinaryVideo("br_av:video_(value_2500k;mode_cbr");
```

```js
new CloudinaryVideo("br_av:video_(value_2500k;mode_cbr");
```

```python
CloudinaryVideo("br_av:video_(value_2500k;mode_cbr").image()
```

```php
(new VideoTag('br_av:video_(value_2500k;mode_cbr'));
```

```java
cloudinary.url().transformation(new Transformation().resourceType("video").imageTag("br_av:video_(value_2500k;mode_cbr");
```

```ruby
cl_image_tag("br_av:video_(value_2500k;mode_cbr", resource_type: "video")
```

```csharp
cloudinary.Api.UrlVideoUp.BuildImageTag("br_av:video_(value_2500k;mode_cbr")
```

```dart
cloudinary.video('br_av:video_(value_2500k;mode_cbr').transformation(Transformation());
```

```swift
cloudinary.createUrl().setResourceType("video").generate("br_av:video_(value_2500k;mode_cbr")
```

```android
MediaManager.get().url().transformation(new Transformation().resourceType("video").generate("br_av:video_(value_2500k;mode_cbr");
```

```flutter
cloudinary.video('br_av:video_(value_2500k;mode_cbr').transformation(Transformation());
```

```kotlin
cloudinary.video {
	publicId("br_av:video_(value_2500k;mode_cbr") 
}.generate()
```

```jquery
$.cloudinary.image("br_av:video_(value_2500k;mode_cbr", {resource_type: "video"})
```

```react_native
new CloudinaryVideo("br_av:video_(value_2500k;mode_cbr");
```;audio_(value_128k)/docs/parrot.mp4 "thumb: w_500")

**See also**: [br (bitrate)](transformation_reference#br_bitrate_value) in the Transformation Reference

### Adaptive bitrate streaming

Adaptive bitrate streaming is a video delivery technique that adjusts the quality of a video stream in real-time according to detected bandwidth and CPU capacity. This enables videos to start quicker, with fewer buffering interruptions, and at the best possible quality for the current device and network connection, to maximize user experience. See [adaptive bitrate streaming](adaptive_bitrate_streaming) documentation for more on how to use this with Cloudinary.

**See also**: [How to optimize image quality](image_optimization#how_to_optimize_image_quality)

## How to optimize video format

As there are many different video formats out there, each one with different characteristics and compression capabilities, choosing the right format for each one of your videos can be a tough task. 

There are a couple of Cloudinary options you can use to address these issues.

* [Use automatic format selection (f_auto)](#automatic_format_selection_f_auto)
* [Set the format when delivering a video](#set_the_format_when_delivering_a_video)

### Automatic format selection (f_auto)

Never use `f_auto` (or the combined `q_auto`/`f_auto`) in an [incoming transformation](eager_and_incoming_transformations#incoming_transformations) or a [named transformation](video_named_transformations#limitations_of_named_transformations). Format selection has to be resolved per request at the CDN during delivery, based on the requesting browser. That can't happen when `f_auto` is requested as part of an upload (an incoming transformation), or when the `f_auto` instruction is stored inside a named transformation definition.

There are a lot of formats and codecs for encoding videos, with some formats better than others at compression and reducing the file size without impairing visual quality. Since different browsers support different video formats and codecs, the best solution to save bandwidth and optimize delivery time would be to deliver the best format according to the browser used by each of your visitors. 

The `fetch_format` parameter can be set to auto (`f_auto` in URLs) in order to perform automatic format and codec selection based on the requesting browser. For example, with the automatic format feature, most of your users with modern browsers would receive a VP9-encoded WebM or AV1 encoded MP4 file. For browsers like Safari, users may receive an HEVC-encoded MP4 file. If a browser does not support the more optimal formats then the video is delivered as an H.264-encoded MP4 file (which is supported by almost every browser).

For example, the uploaded video named `hotel_buffet` scaled down to a height of 280 pixels and delivered as WebM (VP9) or MP4 (AV1) to most browsers (336 KB/244 KB), an MP4 (HEVC) to Safari browsers (349 KB), or as an MP4 (H.264) to browsers with limited support (505 KB):

![Video delivered with f_auto](https://res.cloudinary.com/demo/video/upload/c_scale,h_280/f_auto/docs/hotel_buffet.mp4)

```nodejs
cloudinary.video("docs/hotel_buffet", {transformation: [
  {height: 280, crop: "scale"},
  {fetch_format: "auto"}
  ]})
```

```react
import { scale } from "@cloudinary/url-gen/actions/resize";
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("docs/hotel_buffet.mp4")
  .resize(scale().height(280))
  .delivery(format(auto()));
```

```vue
import { scale } from "@cloudinary/url-gen/actions/resize";
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("docs/hotel_buffet.mp4")
  .resize(scale().height(280))
  .delivery(format(auto()));
```

```angular
import { scale } from "@cloudinary/url-gen/actions/resize";
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("docs/hotel_buffet.mp4")
  .resize(scale().height(280))
  .delivery(format(auto()));
```

```js
import { scale } from "@cloudinary/url-gen/actions/resize";
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("docs/hotel_buffet.mp4")
  .resize(scale().height(280))
  .delivery(format(auto()));
```

```python
CloudinaryVideo("docs/hotel_buffet").video(transformation=[
  {'height': 280, 'crop': "scale"},
  {'fetch_format': "auto"}
  ])
```

```php
use Cloudinary\Transformation\Resize;
use Cloudinary\Transformation\Delivery;
use Cloudinary\Transformation\Format;

(new VideoTag('docs/hotel_buffet.mp4'))
	->resize(Resize::scale()->height(280))
	->delivery(Delivery::format(
	Format::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .height(280).crop("scale").chain()
  .fetchFormat("auto")).videoTag("docs/hotel_buffet");
```

```ruby
cl_video_tag("docs/hotel_buffet", transformation: [
  {height: 280, crop: "scale"},
  {fetch_format: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Height(280).Crop("scale").Chain()
  .FetchFormat("auto")).BuildVideoTag("docs/hotel_buffet")
```

```dart
cloudinary.video('docs/hotel_buffet.mp4').transformation(Transformation()
	.resize(Resize.scale().height(280))
	.delivery(Delivery.format(
	Format.auto())));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setHeight(280).setCrop("scale").chain()
  .setFetchFormat("auto")).generate("docs/hotel_buffet.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .height(280).crop("scale").chain()
  .fetchFormat("auto")).resourceType("video").generate("docs/hotel_buffet.mp4");
```

```flutter
cloudinary.video('docs/hotel_buffet.mp4').transformation(Transformation()
	.resize(Resize.scale().height(280))
	.delivery(Delivery.format(
	Format.auto())));
```

```kotlin
cloudinary.video {
	publicId("docs/hotel_buffet.mp4")
	 resize(Resize.scale() { height(280) })
	 delivery(Delivery.format(
	Format.auto())) 
}.generate()
```

```jquery
$.cloudinary.video("docs/hotel_buffet", {transformation: [
  {height: 280, crop: "scale"},
  {fetch_format: "auto"}
  ]})
```

```react_native
import { scale } from "@cloudinary/url-gen/actions/resize";
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryVideo("docs/hotel_buffet.mp4")
  .resize(scale().height(280))
  .delivery(format(auto()));
```

> **NOTE**:
>
> If you're on a plan that includes [optimization by default settings](optimize_by_default_settings), you can select the **Automatic format** setting instead of including `f_auto` in your URLs.

#### Specifying media type with f_auto

In certain scenarios, it may be necessary to include the media type option to ensure that your video is delivered as a video rather than a still image video frame, or as just audio. By default, `f_auto` will assume all media is an image unless a file extension is included in the URL. You can ensure a video is delivered by using a video file extension such as `mp4`, but when building your URLs using one of our SDKs, you might not use a file extension as part of the public ID.

By setting `f_auto:video`, you can ensure that the asset will be delivered in the optimal video format. For example, to deliver the `sailing_boat` video with automatic format selection, ensuring it is delivered as a video when no file extension is specified:

![Deliver a video with automatic format selection when no file extension provided](https://res.cloudinary.com/demo/video/upload/f_auto:video/docs/sailing_boat "thumb:h_280, poster: https://res.cloudinary.com/demo/video/upload/h_280/docs/sailing_boat.jpg ")

```nodejs
cloudinary.image("docs/sailing_boat", {fetch_format: "auto", resource_type: "video"})
```

```react
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto:video } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage('docs/sailing_boat')
	.delivery(format(
	auto:video()))
	.setAssetType("video");
```

```vue
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto:video } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage('docs/sailing_boat')
	.delivery(format(
	auto:video()))
	.setAssetType("video");
```

```angular
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto:video } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage('docs/sailing_boat')
	.delivery(format(
	auto:video()))
	.setAssetType("video");
```

```js
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto:video } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage('docs/sailing_boat')
	.delivery(format(
	auto:video()))
	.setAssetType("video");
```

```python
CloudinaryVideo("docs/sailing_boat").image(fetch_format="auto")
```

```php
use Cloudinary\Transformation\Delivery;
use Cloudinary\Transformation\Format;

(new ImageTag('docs/sailing_boat'))
	->delivery(Delivery::format(
	Format::auto:video()))
	->assetType("video");
```

```java
cloudinary.url().transformation(new Transformation().fetchFormat("auto")).resourceType("video").imageTag("docs/sailing_boat");
```

```ruby
cl_image_tag("docs/sailing_boat", fetch_format: "auto", resource_type: "video")
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation().FetchFormat("auto")).BuildImageTag("docs/sailing_boat")
```

```dart
cloudinary.image('docs/sailing_boat').transformation(Transformation()
	.delivery(Delivery.format(
	Format.auto:video()))
	.setAssetType("video"));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setFetchFormat("auto")).generate("docs/sailing_boat")
```

```android
MediaManager.get().url().transformation(new Transformation().fetchFormat("auto")).resourceType("video").generate("docs/sailing_boat");
```

```flutter
cloudinary.image('docs/sailing_boat').transformation(Transformation()
	.delivery(Delivery.format(
	Format.auto:video()))
	.setAssetType("video"));
```

```kotlin
cloudinary.image {
	publicId("docs/sailing_boat")
	 delivery(Delivery.format(
	Format.auto:video()))
	 assetType("video") 
}.generate()
```

```jquery
$.cloudinary.image("docs/sailing_boat", {fetch_format: "auto", resource_type: "video"})
```

```react_native
import { format } from "@cloudinary/url-gen/actions/delivery";
import { auto:video } from "@cloudinary/url-gen/qualifiers/format";

new CloudinaryImage('docs/sailing_boat')
	.delivery(format(
	auto:video()))
	.setAssetType("video");
```

> **TIP**: You can also use the media type option to [deliver your video as an animated image](videos_to_animated_images#delivering_animated_images_with_automatic_format_selection).

#### Tips and considerations for using f_auto

* This feature is also available on mobile native applications as long as the specified formats are included in the `Accept` header.
* When using automatic format selection, a derived asset is created for each format that's delivered. This could impact your total [transformation counts](transformation_counts) and storage [usage](admin_api#usage). It also means the first viewer to request each format receives a video that's still being generated, so the player shows the wrong duration and seeking doesn't work. To avoid this, generate the derived assets for each format in advance, as described in [Warm the cache for transformed videos](#warm_the_cache_for_transformed_videos).
* Using `f_auto` in an eager transformation does not eagerly generate derived assets for all formats; see [Using automatic format in eager transformations](eager_and_incoming_transformations#using_automatic_format_in_eager_transformations).
* **AV1 format**: 
  * If your account plan uses the [video seconds metric](developer_onboarding_faq_video_seconds), AV1 format is automatically supported as a possible `f_auto` format.
  * If your account plan uses the **video bandwidth metric**, AV1 is not supported for `f_auto` by default. To discuss options for getting `f_auto` support for AV1, [contact support](https://support.cloudinary.com/hc/en-us/requests/new).
* `f_auto` is not effective if used in a [named transformation](video_named_transformations#limitations_of_named_transformations) or an [incoming transformation](eager_and_incoming_transformations#incoming_transformations), because the format must be resolved per requesting browser at delivery time.

**See also**: [q_auto for images](image_optimization#automatic_format_selection_f_auto)

### Set the format when delivering a video

Using the format parameter (`f_` in URLs) you can explicitly choose the format you'd like the video to be delivered in (e.g `f_webm`) based on your requirements.

For details, see [Transcoding videos to other formats](video_transcoding).

## How to optimize video sizing

The most efficient way to minimize the file size of your delivered videos and improve their performance is to resize them so they'll fit your web or mobile app-specific design.

If it suits your use case, you can also perform the resize before you save the video in Cloudinary using [incoming transformations](eager_and_incoming_transformations#incoming_transformations), this will help save on storage space.

For details on how to resize your videos, see [resizing and cropping videos](video_resizing_and_cropping).

**See also**: [How to optimize image sizing](image_optimization#how_to_optimize_image_sizing)

## Warm the cache for transformed videos

The first time a transformed video is requested, Cloudinary streams it to the viewer while generation is in progress. Because the final file size isn't known yet, the player **shows the wrong duration** and **seeking doesn't work**. After generation completes, the derived video is cached and later requests are delivered normally.

You can tell the two responses apart by their headers:

Header | Generated on the fly (first request) | Already generated |
|---|---|---|
| `content-length` | Absent | The size of the delivered video |
| `accept-ranges` | `none`, so the player has no byte range to seek to | `bytes` |
| `cache-control` | `private, no-transform, no-cache, no-store` | `public, no-transform, max-age=2592000` |

To make sure every viewer, including the first, receives a fully generated video, generate your transformed videos in advance: on upload, using [eager transformations](eager_and_incoming_transformations#eager_transformations), or after upload, using the [explicit method](update_assets#the_explicit_method).

If you deliver videos with `f_auto`, generate an eager transformation for each format and codec, and include a video extension, such as `.mp4`, in the delivery URL. Otherwise, the eager transformations aren't delivered. For details, see [Eager transformations for videos](eager_and_incoming_transformations#eager_transformations_for_videos). Eager transformations aren't supported together with the [optimize by default settings](eager_and_incoming_transformations#eager_transformations_with_optimize_by_default).

If you can't generate a video in advance, add the [no_stream flag](transformation_reference#fl_no_stream) (`fl_no_stream`) to the delivery URL. Cloudinary then waits until the video is fully generated before responding, so playback starts later for the first viewer, but the duration is correct and seeking works.
## Analyze media to improve optimization

After you've applied optimizations, it's worth checking how your assets are actually being delivered so you can catch any that still need attention. Cloudinary gives you two complementary ways to do this. The [**Delivery Reports**](#console_delivery_reports) in your console surface account-wide data on your biggest bandwidth consumers, while the [**Media Inspector**](#chrome_media_inspector_extension) browser extension analyzes the media on any live web page to pinpoint unoptimized, oversized, or incorrectly sized assets.

### Console Delivery Reports

Even after employing as many automated optimization solutions as possible, you may find that some assets and formats are still especially big bandwidth eaters.

Take a look at the **[Delivery Reports](programmable_media_asset_usage_data#reports)** page of the Cloudinary console. From here, you can view detailed information on a variety of data points that can help you understand where to make improvements.

For example, check the **Top Assets** and **Top Delivered Assets** sections, to determine whether you can employ file-specific optimizations on these assets. Alternatively, scroll down to the **Top Browsers** to get an idea of how important each browser is to your users. This can give you insights on the relative value of using newer formats that are only supported on some browsers.

Top Assets

Top Browsers

### Chrome Media Inspector Extension

Install and use the [Cloudinary Media Inspector](media_inspector_browser_extension) browser extension to analyze all media assets on your site and identify optimization opportunities. The Media Inspector helps you find unoptimized assets, oversized files, and other performance issues that may be impacting your site's speed and user experience.

#### Find unoptimized assets

To identify assets that aren't using Cloudinary's automatic optimizations:

1. Click the **Cloudinary Media Inspector** button in your browser's extensions toolbar.
2. In the **Media Overview** page, enter `!f_auto AND !q_auto` in the **URL** search field to filter for assets that aren't using automatic format and quality optimizations.
3. Optionally, add additional filters like `Image` or `Video` in the **Content Type** field to narrow your search.

![Media Inspector view filtered results](https://cloudinary-res.cloudinary.com/image/upload/bo_1px_solid_gray/f_auto/q_auto/docs/inspector_chrome_extension/filtered-image-unoptimized.png "thumb: w_700,dpr_2, width:700, caption: Media Inspector: filter results")

The results show all assets on the page that could benefit from adding [f_auto][f_auto_link] and [q_auto][q_auto_link] to their delivery URLs.

#### Find oversized assets

To identify assets that are larger than necessary:

1. Click the **Cloudinary Media Inspector** button in your browser's extensions toolbar.
2. In the **Media Overview** page, enter a size threshold in the **Size** field, such as `>500000` to find assets over 500 KB.
3. Sort the results by clicking the **Size** heading to see the largest files first.

![Media Inspector view filtered results](https://cloudinary-res.cloudinary.com/image/upload/bo_1px_solid_gray/f_auto/q_auto/docs/inspector_chrome_extension/filtered-sorted-over-500k.png "thumb: w_700,dpr_2, width:700, caption: Media Inspector: filter results")

The information at the bottom of the screen updates based on your filtered results, showing you stats for minimum, maximum, average, and total delivered bytes, in addition to bytes saved.

#### Find incorrectly sized assets

The **Scale Ratio** column in the Media Inspector indicates whether your images and videos are being upscaled, downscaled, or displayed with modified aspect ratios. This helps you identify assets that aren't sized appropriately for their display dimensions.

`scale ratio = served resolution / display resolution`

* **A scale ratio of 1.00** means the asset is served at exactly the right resolution for the display, either because it's stored at the correct resolution, or because it's served with Cloudinary resize transformations applied.

* **A scale ratio less than 1.00** means the asset is being upscaled, which may cause quality issues. {variable:upscaleSolution}

* **A scale ratio greater than 1.00** means the asset is being downscaled. The served asset is larger than required, so delivering this asset uses more bandwidth than required. Consider [resizing][resize_link] these assets in the delivery URL so that they're served at the display size.

![Media Inspector scale ratio greater than 1.00](https://cloudinary-res.cloudinary.com/image/upload/bo_1px_solid_gray/f_auto/q_auto/docs/inspector_chrome_extension/downscale_proportionally.png "thumb: w_300,dpr_2, width:300, caption: Media Inspector: scale ratios")

##### Mismatched width and height scaling

Hovering over the **Scale Ratio** shows you the **Width Ratio** and **Height Ratio** separately, where:

* `width ratio = served width / display width`
* `height ratio = served height / display height`

If the width and height ratios are different, the displayed asset may appear squashed or stretched because the display aspect ratio differs from the source aspect ratio. Consider using a [smart cropping][smart_cropping_link] method to make your video fit the available space without losing important details.

![Media Inspector scale ratio less than 1.00 and mismatched width and height](https://cloudinary-res.cloudinary.com/image/upload/bo_1px_solid_gray/f_auto/q_auto/docs/inspector_chrome_extension/upscaled_stretched.png "thumb: w_300,dpr_2, width:300, caption: Media Inspector: scale ratio elements showing stretching")

For more information on using the Media Inspector, see the [Media Inspector browser extension](media_inspector_browser_extension) documentation.

> **READING**:
>
> For additional reading on video optimization and ways that Cloudinary functionality can help you best optimize your videos, you can also review these blog posts:

> * [New Auto-Quality Setting for Content-Aware Video Compression](https://cloudinary.com/blog/new_auto_quality_setting_for_content_aware_video_compression)

> * [Automatic Video Transcoding](https://cloudinary.com/blog/automatic_video_transcoding)

> * [How to Compress Video Size Automatically With One Line of Code](https://cloudinary.com/blog/how_to_automate_compression_of_video_files_with_one_line_of_code)

> * [Optimizing Video with Cloudinary and the HTML5 video Player: Part 1](https://cloudinary.com/blog/optimizing_video_with_cloudinary_and_the_html5_video_player_part_1)

> * [Video Optimization, Part II: Multi-Codec Adaptive Bitrate Streaming](https://cloudinary.com/blog/video_optimization_part_ii_adaptive_bitrate_streaming_of_multiple_codecs)

> * [Top 10 Mistakes in Handling Website Videos and How to Solve Them](https://cloudinary.com/blog/top_10_mistakes_in_handling_website_videos_and_how_to_solve_them)
