{"id":39622,"date":"2026-01-14T07:00:00","date_gmt":"2026-01-14T15:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=39622"},"modified":"2026-01-20T10:28:03","modified_gmt":"2026-01-20T18:28:03","slug":"1-api-many-outputs-cross-channel-video-repurposing","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing","title":{"rendered":"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System"},"content":{"rendered":"\n<p>I\u2019ve worked on enough campaigns to know that when a team produces one great video, the next step is creating a version for TikTok, YouTube, Instagram, LinkedIn, email, landing pages, etc. In content marketing, this is referred to as <strong>video repurposing<\/strong> or <strong>content recycling<\/strong>.<\/p>\n\n\n\n<p>On paper, reusing a video should be a quick process. You already have the content, so you just tweak it for each channel, right? In reality, it\u2019s just time-consuming.<\/p>\n\n\n\n<p>It\u2019s not that the edits are hard, but they\u2019re repetitive. That pushed me to rethink the whole process and build what I now call my <em>\u201cone API, many outputs\u201d<\/em> setup. It\u2019s not a fancy in-house platform. It&#8217;s just using <a href=\"https:\/\/cloudinary.com\/documentation\/cloudinary_video\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary\u2019s Video API<\/a> to automate your post-production video workflow.<\/p>\n\n\n\n<p>In this post, you\u2019ll learn how to set up the same video workflow using Cloudinary\u2019s Video API, so you can turn one master video into a full set of ready-to-publish assets in minutes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Does a &#8216;1 API, Many Outputs&#8217; System Look Like?<\/h2>\n\n\n\n<p>When I say \u201cone API, many outputs,\u201d I\u2019m referring to a setup where a single master video can be converted into every social media format, without the need to open a video editor even once.<\/p>\n\n\n\n<p>Here\u2019s how the process works:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You upload the master file to <a href=\"https:\/\/cloudinary.com\/documentation\/node_image_and_video_upload\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary<\/a>. That\u2019s the only manual step.<\/li>\n\n\n\n<li>As soon as the master video is uploaded into Cloudinary, the API automatically generates the different versions you\u2019ve defined.<\/li>\n\n\n\n<li>Each version is cropped, branded, captioned, and optimized in the same pass.<\/li>\n\n\n\n<li>The final variants are instantly available via URLs you can drop into your CMS, DAM, or embed directly on a landing page.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1765585953\/1_API_Many_Outputs-1.png\" alt=\"Flow chart showing the one API, many outputs architecture. Starts with Master Video (Upload Once), then Cloudinary Video API: Store, Transform. Delilver. From there, arrows point towards different social media platforms and channels.\"\/><figcaption class=\"wp-element-caption\">One API, many outputs architecture.<\/figcaption><\/figure>\n\n\n\n<p>The key is that Cloudinary\u2019s Video API isn\u2019t just a converter. It stores the original file, applies multiple <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/documentation\/video_manipulation_and_delivery\" rel=\"noreferrer noopener\">transformations<\/a> (crop, overlay, trim, format, and quality settings) in real time or upon upload, and delivers them through a CDN.&nbsp;<\/p>\n\n\n\n<p>The system doesn\u2019t care if you need three formats or 30. It just follows the rules you\u2019ve set. So, instead of \u201cexport, tweak, upload\u201d for each platform, it\u2019s \u201cupload once, use anywhere.\u201d That\u2019s the foundation this workflow is built upon.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How Are the Variants Created?<\/h2>\n\n\n\n<p>Before variants can be created, a master video must be uploaded to Cloudinary. You can use the \u00a0<a href=\"https:\/\/cloudinary.com\/documentation\/node_integration\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary Node.js SDK<\/a>, which can be installed with the command: <code>npm install cloudinary<\/code><\/p>\n\n\n<div class='c-callout  c-callout--inline-title c-callout--note'><strong class='c-callout__title'>Note:<\/strong> <p>Cloudinary <a href=\"https:\/\/cloudinary.com\/documentation\/cloudinary_sdks\">provides SDKs<\/a> for many backend and frontend languages, so you don\u2019t have to use Node.js if that\u2019s not part of your stack.<\/p>\n<\/div>\n\n\n<p>After installing the SDK, you\u2019ll need three credentials: <strong>Cloud Name<\/strong>, <strong>API Key<\/strong>, and <strong>API Secret<\/strong>. These are found in your <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/users\/login\" rel=\"noreferrer noopener\">Cloudinary dashboard<\/a> under the <strong>Settings<\/strong> page:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1765585953\/1_API_Many_Outputs-2.png\" alt=\"Cloudinary dashboard: Under settings, you can find your cloud name, API key, and API secret.\"\/><figcaption class=\"wp-element-caption\">Generate the Cloudinary API key.<\/figcaption><\/figure>\n\n\n\n<p>Pull them into a <code>.env<\/code> file so they don\u2019t end up hardcoded in your scripts:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">CLOUDINARY_CLOUD_NAME=your_cloud_name\n\nCLOUDINARY_API_KEY=your_api_key\n\nCLOUDINARY_API_SECRET=your_api_secret <\/code><\/span><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Project Setup<\/h2>\n\n\n\n<p>Here\u2019s what your project folder should look like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">video-pipeline\/\n\n\u251c\u2500 assets\/\n\n\u2502 \u00a0\u2514\u2500 master_video.mp4 \u00a0 \u00a0 \u00a0 \u00a0<span class=\"hljs-comment\"># your source video<\/span>\n\n\u251c\u2500 .env \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-comment\"># your Cloudinary secrets (never commit)<\/span>\n\n\u251c\u2500 package.json\n\n\u2514\u2500 scripts\/\n\n\u00a0 \u00a0\u2514\u2500 upload.js \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-comment\"># the code you showed<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In package.json, enable ES modules and add a run script:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">{\n\n\u00a0 <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"module\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">\"scripts\"<\/span>: { <span class=\"hljs-attr\">\"upload\"<\/span>: <span class=\"hljs-string\">\"node scripts\/upload.js\"<\/span> }\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then, install the dependencies:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>npm install cloudinary dotenv<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Finally, you can use this upload script in <code>scripts\/upload.js<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'dotenv\/config'<\/span>; <span class=\"hljs-comment\">\/\/ loads .env<\/span>\n\n<span class=\"hljs-comment\">\/\/ Configure Cloudinary from environment variables<\/span>\n\ncloudinary.config({\n\n\u00a0 <span class=\"hljs-attr\">cloud_name<\/span>: process.env.CLOUDINARY_CLOUD_NAME,\n\n\u00a0 <span class=\"hljs-attr\">api_key<\/span>: process.env.CLOUDINARY_API_KEY,\n\n\u00a0 <span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET,\n\n});\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">uploadVideo<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\n\u00a0 <span class=\"hljs-keyword\">try<\/span> {\n\n\u00a0 \u00a0 <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-string\">\"assets\/master_video.mp4\"<\/span>, <span class=\"hljs-comment\">\/\/ Path to your video file<\/span>\n\n\u00a0 \u00a0 \u00a0 {\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>, \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-comment\">\/\/ Must be \"video\" for video uploads<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">public_id<\/span>: <span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, <span class=\"hljs-comment\">\/\/ Optional: specify folder and name<\/span>\n\n\u00a0 \u00a0 \u00a0 }\n\n\u00a0 \u00a0 );\n\n\u00a0 \u00a0 <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"Upload successful:\"<\/span>, result);\n\n\u00a0 } <span class=\"hljs-keyword\">catch<\/span> (error) {\n\n\u00a0 \u00a0 <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">\"Upload failed:\"<\/span>, error);\n\n\u00a0 }\n\n}\n\nuploadVideo();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Run it with: <code>npm run upload<\/code><\/p>\n\n\n\n<p>This runs the code and uploads the master video. Every transformation points back to the same <code>public_id<\/code>, which is the foundation for generating all variants.<\/p>\n\n\n\n<p>Let\u2019s now explore five variants you will most likely need to repurpose your video across different channels, and how to set them up with Cloudinary.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Smart Cropping for Platform Aspect Ratios<\/h2>\n\n\n\n<p>Every platform has its preferred aspect ratio, and getting this right is a key part of video repurposing for social media. Cloudinary\u2019s <code>c_fill<\/code> and <code>g_auto<\/code> use <a href=\"https:\/\/cloudinary.com\/documentation\/content_aware_video_cropping_tutorial\" target=\"_blank\" rel=\"noreferrer noopener\">content-aware cropping<\/a> to automatically detect and keep the subject in focus while fitting it into the target ratio.<\/p>\n\n\n\n<p>From one master video, you can generate all your social-friendly formats with a few simple transformation URLs, like so:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ TikTok 9:16<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> tiktokUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">aspect_ratio<\/span>: <span class=\"hljs-string\">\"9:16\"<\/span>, <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>, <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>, <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> }\n\n\u00a0 ]\n\n});\n\n<span class=\"hljs-comment\">\/\/ YouTube 16:9<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> youtubeUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">aspect_ratio<\/span>: <span class=\"hljs-string\">\"16:9\"<\/span>, <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>, <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>, <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> }\n\n\u00a0 ]\n\n});\n\n<span class=\"hljs-comment\">\/\/ Instagram 1:1<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> instagramUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">aspect_ratio<\/span>: <span class=\"hljs-string\">\"1:1\"<\/span>, <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>, <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>, <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> }\n\n\u00a0 ]\n\n});\n\n<span class=\"hljs-built_in\">console<\/span>.log(tiktokUrl);\n\n<span class=\"hljs-built_in\">console<\/span>.log(youtubeUrl);\n\n<span class=\"hljs-built_in\">console<\/span>.log(instagramUrl);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here&#8217;s what the TikTok output looked like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/video\/upload\/ar_9:16,c_fill,g_auto,q_auto,f_auto\/campaign\/master_video.mp4<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Auto-Captioning and Subtitle Overlays<\/h2>\n\n\n\n<p>On platforms where videos autoplay with sound muted, captions have been crucial for both engagement and accessibility in my projects. Instead of manually transcribing every clip, you can use Cloudinary\u2019s AI transcription add-ons.<\/p>\n\n\n\n<p>For example, here\u2019s how to use the <a href=\"https:\/\/cloudinary.com\/documentation\/google_ai_video_transcription_addon\" target=\"_blank\" rel=\"noreferrer noopener\">Google AI Video Transcription add-on<\/a> to generate a WebVTT (<code>.vtt)<\/code> file at upload time:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(<span class=\"hljs-string\">\"assets\/master_video.mp4\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">public_id<\/span>: <span class=\"hljs-string\">\"campaign\/master_video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">raw_convert<\/span>: <span class=\"hljs-string\">\"google_speech:vtt\"<\/span> <span class=\"hljs-comment\">\/\/ generate WebVTT subtitles<\/span>\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>By adding <code>:vtt<\/code> to the <code>raw_convert<\/code> parameter, Cloudinary creates a <code>.vtt<\/code> file alongside your master video. Once transcription is complete, you\u2019ll have <code>campaign\/master_video.google.vtt<\/code> ready to use automatically.<\/p>\n\n\n\n<p>When you want captions burned directly into the video (for TikTok or ad placements), overlay them with a transformation:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> videoWithSubs = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">overlay<\/span>: <span class=\"hljs-string\">\"subtitles:campaign\/master_video.google.vtt\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">flags<\/span>: <span class=\"hljs-string\">\"layer_apply\"<\/span> }\n\n\u00a0 ]\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The corresponding URL looks like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/video\/upload\/l_subtitles:campaign\/master_video.google.vtt\/fl_layer_apply\/campaign\/master_video.mp4<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If you prefer to let users toggle captions on or off, simply deliver the <code>.vtt<\/code> file separately:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">controls<\/span> <span class=\"hljs-attr\">playsinline<\/span> <span class=\"hljs-attr\">preload<\/span>=<span class=\"hljs-string\">\"metadata\"<\/span>&gt;<\/span>\n\n\u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/&lt;cloud_name&gt;\/video\/upload\/campaign\/master_video.mp4\"<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/mp4\"<\/span>&gt;<\/span>\n\n\u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">track<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/&lt;cloud_name&gt;\/raw\/upload\/campaign\/master_video.google.vtt\"<\/span> <span class=\"hljs-attr\">kind<\/span>=<span class=\"hljs-string\">\"subtitles\"<\/span> <span class=\"hljs-attr\">srclang<\/span>=<span class=\"hljs-string\">\"en\"<\/span> <span class=\"hljs-attr\">label<\/span>=<span class=\"hljs-string\">\"English\"<\/span> <span class=\"hljs-attr\">default<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This way, the video stays clean while captions remain available when needed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preview Clip Generation<\/h2>\n\n\n\n<p>For some campaigns, you may need more than just a static poster. A short teaser clip converts better, as people are more likely to watch a 10-second highlight and then tap through to the full video.<\/p>\n\n\n\n<p>Instead of manually cutting previews for each platform, you can use Cloudinary\u2019s <code>e_preview<\/code> effect to generate them automatically.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> previewUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"preview\"<\/span>, <span class=\"hljs-comment\">\/\/ generates AI-selected preview<\/span>\n\n\u00a0 <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This produces a short, AI-generated highlight reel from your master video, which is ready to embed:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/&lt;cloud_name&gt;\/video\/upload\/e_preview,q_auto,f_auto\/campaign\/master_video.mp4\"<\/span> <span class=\"hljs-attr\">controls<\/span> <span class=\"hljs-attr\">playsinline<\/span> <span class=\"hljs-attr\">loop<\/span> <span class=\"hljs-attr\">muted<\/span> <span class=\"hljs-attr\">preload<\/span>=<span class=\"hljs-string\">\"metadata\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>For longer videos (like talks or tutorials), you can fine-tune the duration and segment length:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> customPreviewUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"preview:duration_15:max_seg_5:min_seg_dur_3\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That configuration gives you a 15-second preview split into five segments of at least three seconds each. Feel free to check out Cloudinary&#8217;s <a target=\"_blank\" href=\"https:\/\/codepen.io\/team\/Cloudinary\/pen\/BaNvNxW\" rel=\"noreferrer noopener\">great example<\/a> on <a target=\"_blank\" href=\"https:\/\/codepen.io\/\" rel=\"noreferrer noopener\">CodePen<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dynamic Overlays for CTAs, Logos, and Campaign Messaging<\/h2>\n\n\n\n<p>Sometimes the base video isn\u2019t enough. In ad campaigns, you often need to layer in a call-to-action (\u201cShop Now\u201d), a promo code, or a brand logo. Doing that with a video editor slows everything down as every small tweak means re-exporting and re-uploading.&nbsp;<\/p>\n\n\n\n<p>Instead, you can layer text, images, or branding elements dynamically with Cloudinary\u2019s transformation URLs. This allows you to test creative variations directly in the browser or your CMS, without another round of editing.<\/p>\n\n\n\n<p>Here\u2019s an example that places a \u201cNew Arrivals\u201d text banner at the bottom of your video:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> overlayUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">overlay<\/span>: <span class=\"hljs-string\">\"text:roboto_250_bold:New Arrivals\"<\/span>, <span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-string\">\"black\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"south\"<\/span>, <span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-number\">0.15<\/span>, <span class=\"hljs-attr\">flags<\/span>: <span class=\"hljs-string\">\"layer_apply\"<\/span> }\n\n\u00a0 ]\n\n});\n\n<span class=\"hljs-built_in\">console<\/span>.log(overlayUrl);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That outputs a URL like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/video\/upload\/l_text:roboto_250_bold:New%20Arrivals,co_black,fl_layer_apply,g_south,y_0.15\/campaign\/master_video.mp4<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Drop that into a <code>&lt;video><\/code> tag, and you\u2019ve got a branded clip. To make it more engaging, animate your overlay with fade effects:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> animatedOverlayUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">overlay<\/span>: <span class=\"hljs-string\">\"text:roboto_250_bold:New Arrivals\"<\/span>, <span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-string\">\"black\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">duration<\/span>: <span class=\"hljs-number\">7.5<\/span>, <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"fade:1000\"<\/span> }, <span class=\"hljs-comment\">\/\/ fade in over 1s<\/span>\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"fade:-1000\"<\/span> }, \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-comment\">\/\/ fade out over 1s<\/span>\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"south\"<\/span>, <span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-number\">0.15<\/span>, <span class=\"hljs-attr\">flags<\/span>: <span class=\"hljs-string\">\"layer_apply\"<\/span> }\n\n\u00a0 ]\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This creates a 7.5-second text overlay that animates in and out, making the call-to-action feel more engaging.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1765585954\/1_API_Many_Outputs-3.gif\" alt=\"Dynamic overlay demo of &quot;New Arrivals&quot; over a GIF of four men wearing plain white T-shirts and jeans.\"\/><figcaption class=\"wp-element-caption\">Dynamic overlay demo.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Automatic Transcoding and Adaptive Streaming<\/h2>\n\n\n\n<p>One of the biggest workflow wins comes from letting <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/blog\/automatic_video_transcoding\" rel=\"noreferrer noopener\">Cloudinary handle transcoding<\/a> automatically. Normally, you\u2019d have to export multiple versions of a video (MP4 for Safari, WebM for Chrome, HEVC for iOS, etc.). Instead, you can upload once, and Cloudinary will deliver the right format for each device and browser.<\/p>\n\n\n\n<p>Add <code>f_auto<\/code> to your delivery URL to let Cloudinary choose the optimal codec (VP9, HEVC, H.264, AV1, etc.) on the fly:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> autoFormatUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>\n\n});\n\n<span class=\"hljs-built_in\">console<\/span>.log(autoFormatUrl);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This results in Chrome users getting VP9-encoded WebM, Safari getting HEVC-encoded MP4, and older browsers falling back to H.264, all from the same original asset.<\/p>\n\n\n\n<p>You can pair this with <code>q_auto<\/code> for content-aware compression. Cloudinary analyzes the video and delivers the lowest bitrate that still looks sharp.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> optimizedUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That one change consistently reduces file sizes by 20-40% without requiring manual bitrate adjustments.<\/p>\n\n\n\n<p>For longer content or when bandwidth fluctuates, use <a href=\"https:\/\/cloudinary.com\/documentation\/adaptive_bitrate_streaming\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary\u2019s adaptive streaming<\/a> feature. Request an HLS (.m3u8) or DASH (.mpd) manifest with <code>sp_auto<\/code> to deliver multiple renditions at different bitrates automatically:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> hlsUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video.m3u8\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">streaming_profile<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This means that a user with a fast connection might see 1080p or 4K, while someone with a slow mobile connection gets a lower-quality 480p stream, without you having to build or manage separate files.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How is This Connected to Your CMS, DAM, or Deployment Workflows?<\/h2>\n\n\n\n<p>Once the transformation logic worked in isolation, the next challenge was automating it as part of a larger content pipeline.<\/p>\n\n\n\n<p>I didn\u2019t want to manually call Cloudinary every time a video was added. The goal is to have the whole system triggered automatically by CMS or DAM events.<\/p>\n\n\n\n<p>To make that happen, you can connect four key pieces: <strong>asset naming<\/strong>, <strong>transformation presets<\/strong>, <strong>webhooks or scheduled jobs<\/strong>, and <strong>caching + analytics<\/strong>. Here\u2019s how each one fits in.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Asset Naming Conventions<\/h3>\n\n\n\n<p>Start by giving every uploaded video a predictable <code>public_id<\/code> pattern.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>projectName\/channelName\/campaignName\/assetSlug<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This way, your CMS can reference the master asset by ID, and the delivery URLs can be constructed on the fly without needing to look anything up.<\/p>\n\n\n\n<p>For example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>marketing\/tiktok\/black-friday\/sneaker-drop<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>From this ID alone, you can tell where it belongs and which transformation presets to apply. You can also attach <strong>metadata<\/strong> and <strong>tags<\/strong> at upload so non-dev tools can discover things:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(<span class=\"hljs-string\">\"assets\/master.mp4\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">public_id<\/span>: <span class=\"hljs-string\">\"prod\/brandx\/black-friday\/master\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">tags<\/span>: &#91;<span class=\"hljs-string\">\"campaign:black-friday\"<\/span>, <span class=\"hljs-string\">\"brand:brandx\"<\/span>, <span class=\"hljs-string\">\"type:master\"<\/span>],\n\n\u00a0 <span class=\"hljs-attr\">context<\/span>: <span class=\"hljs-string\">\"alt=Black Friday master|owner=marketing|locale=en\"<\/span>,\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Transformation Presets<\/h3>\n\n\n\n<p>Rather than hardcoding crop and overlay parameters everywhere, create <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference\" rel=\"noreferrer noopener\">named transformations<\/a> in Cloudinary. This gives me one edit point when a platform specification changes.<\/p>\n\n\n\n<p>Here\u2019s an example of creating a named transformation:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"cloudinary\"<\/span>;\n\n<span class=\"hljs-keyword\">await<\/span> cloudinary.api.create_transformation(\n\n\u00a0 <span class=\"hljs-string\">\"tiktok_vertical\"<\/span>, \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<span class=\"hljs-comment\">\/\/ name you\u2019ll use in URLs<\/span>\n\n\u00a0 { <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 \u00a0 { <span class=\"hljs-attr\">aspect_ratio<\/span>: <span class=\"hljs-string\">\"9:16\"<\/span>, <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>, <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> }, <span class=\"hljs-comment\">\/\/ smart crop<\/span>\n\n\u00a0 \u00a0 \u00a0 { <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"preview:duration_6:max_seg_2:min_seg_dur_1\"<\/span> }, <span class=\"hljs-comment\">\/\/ teaser<\/span>\n\n\u00a0 \u00a0 \u00a0 { <span class=\"hljs-attr\">overlay<\/span>: <span class=\"hljs-string\">\"logo_main\"<\/span>, <span class=\"hljs-attr\">flags<\/span>: <span class=\"hljs-string\">\"layer_apply\"<\/span>, <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"north_west\"<\/span>, <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">200<\/span> },\n\n\u00a0 \u00a0 \u00a0 { <span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-string\">\"white\"<\/span>, <span class=\"hljs-attr\">overlay<\/span>: <span class=\"hljs-string\">\"text:Roboto_60_bold:Shop%20Now\"<\/span> },\n\n\u00a0 \u00a0 \u00a0 { <span class=\"hljs-attr\">flags<\/span>: <span class=\"hljs-string\">\"layer_apply\"<\/span>, <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"south\"<\/span>, <span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-number\">30<\/span> }\n\n\u00a0 \u00a0 ]}\n\n);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In your CMS, store only the <code>public_id<\/code> and the variant name. Then, when you render the asset, simply call:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/video\/upload\/t_tiktok_vertical\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">public_id<\/span>&gt;<\/span>.mp4<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, when you change the preset in Cloudinary, every place that uses it updates instantly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Webhooks or Scheduled Jobs<\/h3>\n\n\n\n<p>You can set up a <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/documentation\/notifications\" rel=\"noreferrer noopener\">webhook endpoint<\/a> so that when a master video finishes uploading or an eager transformation completes, Cloudinary pings your backend:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">app.post(<span class=\"hljs-string\">\"\/hooks\/cloudinary\"<\/span>, express.urlencoded({ extended: <span class=\"hljs-keyword\">true<\/span> }), (req, res) =&gt; {\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> { public_id } = req.body;\n\n\u00a0 cms.markAssetReady(public_id);\n\n\u00a0 ci.triggerBuild();\n\n\u00a0 res.sendStatus(<span class=\"hljs-number\">200<\/span>);\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>For recurring updates, such as swapping out overlays with new promotional text, schedule a nightly job that regenerates URLs for affected assets and sends a HEAD request to warm the CDN caches.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Caching and Analytics<\/h3>\n\n\n\n<p>Cloudinary\u2019s <code>\/v&lt;timestamp>\/<\/code> URL versioning handles cache-busting when assets change. Always deliver with <code>f_auto,q_auto,sp_auto<\/code> so devices get the best format and bitrate automatically:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>...\/video\/upload\/sp_auto,q_auto,f_auto\/t_tiktok_vertical\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">public_id<\/span>&gt;<\/span>.m3u8<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>From there, you can use <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/documentation\/assets_onboarding_dashboard_reports_tutorial\" rel=\"noreferrer noopener\">Delivery Reports<\/a> to see which variants actually get watched and tie that data back to your CMS analytics to decide which presets to keep or drop.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1765585953\/1_API_Many_Outputs-4.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Analyze the most frequently used transformations in Cloudinary\u2019s analytics.<\/figcaption><\/figure>\n\n\n\n<p>Now that you\u2019ve seen each piece separately, here\u2019s how it all comes together in one transformation call.<\/p>\n\n\n\n<p>Here\u2019s an example that turns one master video into a platform-ready asset:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Smart crop to 9:16 for vertical platforms.<\/li>\n\n\n\n<li>Add a \u201cShop Now\u201d call-to-action overlay.<\/li>\n\n\n\n<li>Apply content-aware compression (<code>q_auto<\/code>) and automatic format selection (<code>f_auto<\/code>).<\/li>\n\n\n\n<li>Deliver as either MP4 or HLS for adaptive streaming.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> fullWorkflowUrl = cloudinary.url(<span class=\"hljs-string\">\"campaign\/master_video.m3u8\"<\/span>, {\n\n\u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"video\"<\/span>,\n\n\u00a0 <span class=\"hljs-attr\">transformation<\/span>: &#91;\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">aspect_ratio<\/span>: <span class=\"hljs-string\">\"9:16\"<\/span>, <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>, <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-number\">1280<\/span> },\n\n\u00a0 \u00a0 {<span class=\"hljs-attr\">overlay<\/span>: { <span class=\"hljs-attr\">font_family<\/span>: <span class=\"hljs-string\">\"Arial\"<\/span>, <span class=\"hljs-attr\">font_size<\/span>: <span class=\"hljs-number\">80<\/span>, <span class=\"hljs-attr\">font_weight<\/span>: <span class=\"hljs-string\">\"bold\"<\/span>, <span class=\"hljs-attr\">text<\/span>: <span class=\"hljs-string\">\"Shop Now\"<\/span> }, <span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-string\">\"#ffffff\"<\/span>},\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">duration<\/span>: <span class=\"hljs-number\">7.5<\/span>, <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"fade:1000\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"fade:-1000\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">\"fade:-1000\"<\/span>, <span class=\"hljs-attr\">duration<\/span>: <span class=\"hljs-number\">7.5<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"south\"<\/span>, <span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-number\">0.15<\/span>, <span class=\"hljs-attr\">flags<\/span>: <span class=\"hljs-string\">\"layer_apply\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>, <span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> },\n\n\u00a0 \u00a0 { <span class=\"hljs-attr\">streaming_profile<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> }\n\n\u00a0 ]\n\n});\n\n<span class=\"hljs-built_in\">console<\/span>.log(fullWorkflowUrl);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This is what the MP4 URL looks like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/video\/upload\/ar_9:16,c_fill,h_1280,q_auto,f_auto\/l_text:Arial_80_bold:Shop%20Now\/co_rgb:ffffff\/e_fade:1000\/e_fade:-1000\/du_7.5\/fl_layer_apply,g_south,y_0.15\/campaign\/master_video.mp4<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With this one API call, the video is ready for any channel. This is the power of building a cross-channel video repurposing workflow with Cloudinary.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1765585954\/1_API_Many_Outputs-5.gif\" alt=\"Demo of using the one API for transformations. The aspect ratio is changed to 9:16.\"\/><figcaption class=\"wp-element-caption\">Demo of using one API for transformations.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What Are the Real Benefits of This Approach?<\/h2>\n\n\n\n<p>Faster turnaround, cleaner workflows, and videos that just work everywhere. What\u2019s not to love? But to make it crystal clear, here are some standout wins of this cross-channel video repurposing system:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Drastically reduced time-to-publish<\/strong><strong>.<\/strong> No more manual cropping, re-exporting, and re-uploading for each platform. A single transformation call outputs all the versions you need in minutes, rather than hours or days.<\/li>\n\n\n\n<li><strong>Consistent branding across formats<\/strong><strong>.<\/strong> Logos, lower-thirds, watermarks, and call-to-action overlays appear identically on every variant, so your visual identity is preserved whether the video is on TikTok, YouTube, Instagram, or your own site.<\/li>\n\n\n\n<li><strong>Better SEO through faster, mobile-ready video.<\/strong> Cloudinary\u2019s automatic compression (<code>q_auto<\/code>) and format optimization (f_auto) keep file sizes small and load times fast, which search engines reward. Mobile viewers also get versions tailored to their devices without extra work on your end.<\/li>\n\n\n\n<li><strong>Improved developer-marketer collaboration<\/strong><strong>.<\/strong> Instead of passing video files back and forth, marketing teams can request changes (like an updated overlay or subtitle) that developers implement once in code. The system then automatically regenerates every variant, creating a scalable video content workflow.<\/li>\n\n\n\n<li><strong>Built-in accessibility and localization<\/strong><strong>.<\/strong> Subtitles, captions, and multi-language tracks can be added and baked into any variant, ensuring your content is inclusive and ready for global audiences from day one.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>Repurposing video across channels doesn\u2019t have to mean endless exports and edits. By automating transformations with Cloudinary\u2019s Video API, you can publish faster, stay on brand, and scale creative output effortlessly.<\/p>\n\n\n\n<p>Whether you\u2019re a marketer looking to simplify video workflows or a developer integrating automation into your CMS, a \u201cone API, many outputs\u201d system gives you a repeatable, time-saving foundation. <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/contact\" rel=\"noreferrer noopener\">Contact us today to learn more<\/a>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Resources:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/content_aware_video_cropping_tutorial\" target=\"_blank\" rel=\"noreferrer noopener\">Content-aware video cropping<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/blog\/automatic_video_transcoding\" target=\"_blank\" rel=\"noreferrer noopener\">Automatic Video Transcoding With Cloudinary<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference\" target=\"_blank\" rel=\"noreferrer noopener\">Transformation URL API reference<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/blog\/auto_generate_video_previews_with_great_results_every_time\" target=\"_blank\" rel=\"noreferrer noopener\">Intelligent Video Previews on Cloudinary<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>I\u2019ve worked on enough campaigns to know that when a team produces one great video, the next step is creating a version for TikTok, YouTube, Instagram, LinkedIn, email, landing pages, etc. In content marketing, this is referred to as video repurposing or content recycling. On paper, reusing a video should be a quick process. You [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":39707,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[337,303,305,304],"class_list":["post-39622","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-accessibility","tag-video","tag-video-api","tag-video-transformation"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System<\/title>\n<meta name=\"description\" content=\"Repurposing video for many platforms is slow and repetitive. Learn how to build a \u201cone API, many outputs\u201d system to automate it in minutes.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System\" \/>\n<meta property=\"og:description\" content=\"Repurposing video for many platforms is slow and repetitive. Learn how to build a \u201cone API, many outputs\u201d system to automate it in minutes.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-14T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-01-20T18:28:03+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System\",\"datePublished\":\"2026-01-14T15:00:00+00:00\",\"dateModified\":\"2026-01-20T18:28:03+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing\"},\"wordCount\":1990,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA\",\"keywords\":[\"Accessibility\",\"Video\",\"Video API\",\"Video Transformation\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing\",\"url\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing\",\"name\":\"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA\",\"datePublished\":\"2026-01-14T15:00:00+00:00\",\"dateModified\":\"2026-01-20T18:28:03+00:00\",\"description\":\"Repurposing video for many platforms is slow and repetitive. Learn how to build a \u201cone API, many outputs\u201d system to automate it in minutes.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System","description":"Repurposing video for many platforms is slow and repetitive. Learn how to build a \u201cone API, many outputs\u201d system to automate it in minutes.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing","og_locale":"en_US","og_type":"article","og_title":"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System","og_description":"Repurposing video for many platforms is slow and repetitive. Learn how to build a \u201cone API, many outputs\u201d system to automate it in minutes.","og_url":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing","og_site_name":"Cloudinary Blog","article_published_time":"2026-01-14T15:00:00+00:00","article_modified_time":"2026-01-20T18:28:03+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System","datePublished":"2026-01-14T15:00:00+00:00","dateModified":"2026-01-20T18:28:03+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing"},"wordCount":1990,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA","keywords":["Accessibility","Video","Video API","Video Transformation"],"inLanguage":"en-US","copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing","url":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing","name":"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA","datePublished":"2026-01-14T15:00:00+00:00","dateModified":"2026-01-20T18:28:03+00:00","description":"Repurposing video for many platforms is slow and repetitive. Learn how to build a \u201cone API, many outputs\u201d system to automate it in minutes.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/1-api-many-outputs-cross-channel-video-repurposing#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"1 API, Many Outputs: How I Built a Cross-Channel Video Repurposing System"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1768335547\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API\/Blog_How_I_Built_a_Cross-Channel_Video_Repurposing_System_With_1_API.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39622","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=39622"}],"version-history":[{"count":1,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39622\/revisions"}],"predecessor-version":[{"id":39623,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39622\/revisions\/39623"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/39707"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=39622"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=39622"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=39622"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}