Conditional video transformations
You can define conditional expressions and then apply video transformations only if the specified condition is met, and otherwise either deliver the original video as-is or apply an alternative transformation.
Conditional transformation overview
A conditional transformation is one that is performed only if a specified condition is met. There are a variety of condition options you can use:
- In the most basic form, you define a single condition and a single transformation result if the condition is met. No transformation occurs if the condition is not met.
- You can create more complex expressions with multiple conditions using AND/OR conjunction operators in your IF condition.
- You can include multiple chained transformations in your conditional transformation.
- You can optionally define an ELSE transformation to use when the IF condition is false.
- You can also include arithmetic operations or user-defined variables in the IF or THEN part of your conditional transformation, but only certain video parameters are supported with these expressions and additional limitations apply. For details, see User-defined video variables.
The basic syntax for a conditional transformation is:
if_<video parameter>_<operator>_<value>,<transformations to apply if true>
Where:
video parameter
: A supported video parameter to evaluate in the IF statement, for examplew
(orwidth
in SDKs).comparison operator
: The comparison operator for the IF statement, for examplelt
for 'less than' (or<
in SDKs).value
: A specific value, a supported user-defined variable, or you can compare one parameter with another. For example, if you only want to apply a transformation to non-square videos, you could check if the width of your video is not equal to the height:if_w_ne_h,...
.transformations to apply
: For the simple syntax shown above, you can specify any supported video transformations within a single component.
If your 'THEN' transformation requires chaining, use theif_end
syntax described in: IF > THEN with chained transformations.
Specify strings for a video parameter sub-element or value surrounded by ! !
. For example, if_ if_ctx:!productType!_eq_!shoes!
.
!!
.
For example:
if some-condition_eq_!!
Quick example
both of the videos below have the same conditional transformation applied: It checks if the video is wider than 400 pixels, and if so, overlays a thumbs-up icon at the top-right of the video. Since the first video is a full size HD video, it gets the icon. However, the second video is only 350 pixels wide, so it does not meet the condition and no icon is added.
Supported video condition parameters
Characteristic | Description |
---|---|
w |
(also width in SDKs) The asset's current width. |
iw |
The asset's initial width. |
h |
(also height in SDKs) The asset's current height. |
ih |
The asset's initial height. |
ar |
(also aspect_ratio in SDKs) The aspect ratio of the asset. The compared value can be either decimal (e.g., 1.5) or a ratio (e.g., 3:4). |
iar |
The asset's initial aspect ratio. |
ctx |
A context value assigned to an asset. |
md |
A structured metadata value assigned to an asset. |
tags |
The set of tags assigned to the asset. |
du |
(also duration in SDKs) The current duration of the video. |
idu |
The video's initial duration. |
Supported comparison operators
URL | SDK symbol | Description |
---|---|---|
eq |
= |
Equal to |
ne |
!= |
Not equal to |
lt |
< |
Less than |
gt |
> |
Greater than |
lte |
<= |
Less than or equal to |
gte |
>= |
Greater than or equal to |
in |nin |
in |nin |
Included in | Not included in Compares a set of strings against another set of strings. See Using the in and nin operators for examples. |
When working with the Cloudinary SDKs, you can specify the condition using the SDK characteristic names and operator symbols, or you can specify it using the URL format. For example, both of the following are valid:
- { if: "w_gt_1000", crop: "scale", width: 500}
- { if: "width > 1000", crop: "scale", width: 500}
Using the in and nin operators
The in
and nin
operators compare two sets of strings. The :
delimiter between strings denotes AND.
String sets can include tags, contextual metadata or structured metadata values, for example:
- To determine if
sale
andin_stock
are present in the tags of a particular asset, use:if_!sale:in_stock!_in_tags
. - To determine if the key named
color
exists in the contextual metadata of a particular asset, use:if_!color!_in_ctx
. - To determine if a structured metadata field with external ID,
color-id
, has been set for a particular asset, use:if_!color-id!_in_md
. - To determine if a list value with external ID,
green-id
, has been selected from a multiple-selection structured metadata field with external ID,colors-id
, for a particular asset, use:if_!green-id!_in_md!colors-id!
.
Multiple IF conditions with AND, OR
You can specify multiple conditions to evaluate by joining the conditions with AND or OR conjunction operators.
The example below checks whether the video's aspect ratio is larger than a standard mobile portrait orientation AND if it has a large width. Only in this case, it crops the video to a portrait orientation with a width of 1000. If the video is already has a portrait orientation (condition 1 is false) or if the original width is less than 1000 (condition 2 is false), the conditional transformation is ignored and the video is delivered in its original shape and size.
IF > THEN with chained transformations
If your conditional transformation (the THEN part of your IF-THEN condition) requires chaining, you can use the end_if
syntax to indicate where the IF>THEN condition ends. In this case, only your condition should appear in the first component of the chain, followed by all chained transformations to apply if the condition is true, followed by an if_end
component:
if_<video parameter>_<operator>_<value>/<If true transformation1>/<If true chained transformation2>/<if_end>
You can optionally add additional chained transformations after the if_end
to apply additional transformations to the result of the conditional transformation. However, you cannot append another conditional transformation after the end_if
, nor can you nest If
conditions.
The example below checks whether the video asset's tags include a 'cloudinary' tag. If so, a chained transformation including an image overlay (Cloudinary logo) and a text overlay are applied. If 'cloudinary' is not one of the tags, no transformation would be applied.
Note that this example also includes a scale-down transformation before the beginning of the conditional transformation and a duration trim after the end of the conditional transformation. Those transformations are applied regardless of the true or false result of the condition.
cl_video_tag("snow_horses", :transformation=>[ {:width=>500, :crop=>"scale"}, {:if=>"!cloudinary!_in_tags"}, {:overlay=>"cloudinary_icon_white", :width=>100, :gravity=>"north_east", :opacity=>50, :effect=>"brightness:100"}, {:overlay=>{:font_family=>"arial", :font_size=>15, :text=>"By%20Cloudinary"}, :gravity=>"north_east", :y=>10, :x=>105}, {:if=>"end"}, {:duration=>"5"} ])
cl_video_tag("snow_horses", array("transformation"=>array( array("width"=>500, "crop"=>"scale"), array("if"=>"!cloudinary!_in_tags"), array("overlay"=>"cloudinary_icon_white", "width"=>100, "gravity"=>"north_east", "opacity"=>50, "effect"=>"brightness:100"), array("overlay"=>array("font_family"=>"arial", "font_size"=>15, "text"=>"By%20Cloudinary"), "gravity"=>"north_east", "y"=>10, "x"=>105), array("if"=>"end"), array("duration"=>"5") )))
CloudinaryVideo("snow_horses").video(transformation=[ {'width': 500, 'crop': "scale"}, {'if': "!cloudinary!_in_tags"}, {'overlay': "cloudinary_icon_white", 'width': 100, 'gravity': "north_east", 'opacity': 50, 'effect': "brightness:100"}, {'overlay': {'font_family': "arial", 'font_size': 15, 'text': "By%20Cloudinary"}, 'gravity': "north_east", 'y': 10, 'x': 105}, {'if': "end"}, {'duration': "5"} ])
cloudinary.video("snow_horses", {transformation: [ {width: 500, crop: "scale"}, {if: "!cloudinary!_in_tags"}, {overlay: "cloudinary_icon_white", width: 100, gravity: "north_east", opacity: 50, effect: "brightness:100"}, {overlay: {font_family: "arial", font_size: 15, text: "By%20Cloudinary"}, gravity: "north_east", y: 10, x: 105}, {if: "end"}, {duration: "5"} ]})
cloudinary.url().transformation(new Transformation() .width(500).crop("scale").chain() .if("!cloudinary!_in_tags").chain() .overlay(new Layer().publicId("cloudinary_icon_white")).width(100).gravity("north_east").opacity(50).effect("brightness:100").chain() .overlay(new TextLayer().fontFamily("arial").fontSize(15).text("By%20Cloudinary")).gravity("north_east").y(10).x(105).chain() .if("end").chain() .duration("5")).videoTag("snow_horses");
cloudinary.videoTag('snow_horses', {transformation: [ {width: 500, crop: "scale"}, {if: "!cloudinary!_in_tags"}, {overlay: new cloudinary.Layer().publicId("cloudinary_icon_white"), width: 100, gravity: "north_east", opacity: 50, effect: "brightness:100"}, {overlay: new cloudinary.TextLayer().fontFamily("arial").fontSize(15).text("By%20Cloudinary"), gravity: "north_east", y: 10, x: 105}, {if: "end"}, {duration: "5"} ]}).toHtml();
$.cloudinary.video("snow_horses", {transformation: [ {width: 500, crop: "scale"}, {if: "!cloudinary!_in_tags"}, {overlay: new cloudinary.Layer().publicId("cloudinary_icon_white"), width: 100, gravity: "north_east", opacity: 50, effect: "brightness:100"}, {overlay: new cloudinary.TextLayer().fontFamily("arial").fontSize(15).text("By%20Cloudinary"), gravity: "north_east", y: 10, x: 105}, {if: "end"}, {duration: "5"} ]})
<Video publicId="snow_horses" > <Transformation width="500" crop="scale" /> <Transformation if="!cloudinary!_in_tags" /> <Transformation overlay="cloudinary_icon_white" width="100" gravity="north_east" opacity="50" effect="brightness:100" /> <Transformation overlay={{fontFamily: "arial", fontSize: 15, text: "By%20Cloudinary"}} gravity="north_east" y="10" x="105" /> <Transformation if="end" /> <Transformation duration="5" /> </Video>
<cld-video publicId="snow_horses" > <cld-transformation width="500" crop="scale" /> <cld-transformation if="!cloudinary!_in_tags" /> <cld-transformation overlay="cloudinary_icon_white" width="100" gravity="north_east" opacity="50" effect="brightness:100" /> <cld-transformation overlay={{fontFamily: "arial", fontSize: 15, text: "By%20Cloudinary"}} gravity="north_east" y="10" x="105" /> <cld-transformation if="end" /> <cld-transformation duration="5" /> </cld-video>
<cl-video public-id="snow_horses" > <cl-transformation width="500" crop="scale"> </cl-transformation> <cl-transformation if="!cloudinary!_in_tags"> </cl-transformation> <cl-transformation overlay="cloudinary_icon_white" width="100" gravity="north_east" opacity="50" effect="brightness:100"> </cl-transformation> <cl-transformation overlay="text:arial_15:By%20Cloudinary" gravity="north_east" y="10" x="105"> </cl-transformation> <cl-transformation if="end"> </cl-transformation> <cl-transformation duration="5"> </cl-transformation> </cl-video>
cloudinary.Api.UrlVideoUp.Transform(new Transformation() .Width(500).Crop("scale").Chain() .If("!cloudinary!_in_tags").Chain() .Overlay(new Layer().PublicId("cloudinary_icon_white")).Width(100).Gravity("north_east").Opacity(50).Effect("brightness:100").Chain() .Overlay(new TextLayer().FontFamily("arial").FontSize(15).Text("By%20Cloudinary")).Gravity("north_east").Y(10).X(105).Chain() .If("end").Chain() .Duration("5")).BuildVideoTag("snow_horses")
MediaManager.get().url().transformation(new Transformation() .width(500).crop("scale").chain() .if("!cloudinary!_in_tags").chain() .overlay(new Layer().publicId("cloudinary_icon_white")).width(100).gravity("north_east").opacity(50).effect("brightness:100").chain() .overlay(new TextLayer().fontFamily("arial").fontSize(15).text("By%20Cloudinary")).gravity("north_east").y(10).x(105).chain() .if("end").chain() .duration("5")).resourceType("video").generate("snow_horses.mp4");
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation() .setWidth(500).setCrop("scale").chain() .setIf("!cloudinary!_in_tags").chain() .setOverlay("cloudinary_icon_white").setWidth(100).setGravity("north_east").setOpacity(50).setEffect("brightness:100").chain() .setOverlay("text:arial_15:By%20Cloudinary").setGravity("north_east").setY(10).setX(105).chain() .setIf("end").chain() .setDuration("5")).generate("snow_horses.mp4")
- When your conditional transformation also includes an if_else branch, then the
if_else
component also behaves as anif_end
, and therefore noif_end
component is necessary. - When you use variable or conditional expressions that include the
tags
,ctx
ormd
parameters, their values are exposed publicly in the URL. If you want to prevent such values from being exposed, you can disable the Usage of tags/context/metadata in transformation URLs option in the Security tab of your account settings (enabled by default). When this setting is disabled, any URL that exposes tags, context or metadata values will return an error.
Else branch transformations
You can specify an alternative transformation to apply if the initial condition evaluates as false (and hence the transformations associated with the condition are not applied). To do this, use the if_else
parameter to specify the fallback transformation.
For example, the following conditional transformation checks whether a video's aspect ratio is close to the desired aspect ratio, if it is close, then when the video is resized, any necessary padding is black. But if the aspect ratio is much smaller (for example, if it is a square or portrait video), then a blurred video padding is added.
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation() .setIf("ar_gt_1.2").setHeight(320).setWidth(480).setBackground("black").setCrop("pad").chain() .setIf("else").setHeight(320).setWidth(480).setBackground("blurred:400:15").setCrop("pad")).generate("docs/parrot.mp4")