> ## 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

# Cloudinary Image & Video Release Notes: July 9, 2026



## Cloudinary Image

### Generate images from natural language with Image Generation

The new [Cloudinary Image Generation add-on](image_generation_addon) lets you generate images from natural language text prompts using a unified API that supports multiple AI model families. Choose from photorealistic, illustrative, campaign-focused, and text-rendering models to suit your use case.

Generated images are automatically stored in your Cloudinary product environment as native assets so that you can manage them just like any other asset: apply tags, add metadata, and include them in workflows. Then deliver, transform, and optimize them on the fly.

You can generate images directly from the [Image Generation](https://console.cloudinary.com/app/image/generation) page in the Cloudinary Console or via API.

**Generate an image in the UI**:

![Image Generation details page](https://cloudinary-res.cloudinary.com/image/upload/bo_1px_solid_gray/f_auto/q_auto/docs/image_generation_details.png "thumb: c_scale,w_600,dpr_2, width:600")

**Generate an image via API**:

This request generates a high-resolution product image and stores it permanently in your product environment. Once generated, you can serve any crop or format using Cloudinary's dynamic URL transformations, with no re-generation needed.

```bash
curl -X POST https://api.cloudinary.com/v2/generate/<CLOUD_NAME>/text_to_image \
  -u "<API_KEY>:<API_SECRET>" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A high-end product shot of a luxury watch floating in water, hyper-detailed, sleek commercial photography.",
    "model": {
      "family": "flux",
      "tier": "premium"
    },
    "image_size": {
      "resolution": "4K"
    },
    "target": {
      "target_type": "managed_asset",
      "public_id": "campaigns/summer_launch"
    }
  }'
```

**Example**: Serve the generated image as a web banner (32:9, Horizontal, Smart Cropped):

![Web banner resize of AI generated luxury watch product shot](https://res.cloudinary.com/demo/image/upload/c_auto,g_auto,h_540,w_1920/f_auto/q_auto/campaigns/summer_launch "thumb:c_scale,w_600")

```nodejs
cloudinary.image("campaigns/summer_launch", {transformation: [
  {gravity: "auto", height: 540, width: 1920, crop: "auto"},
  {quality: "auto"}
  ]})
```

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

new CloudinaryImage("campaigns/summer_launch")
  .resize(
    auto()
      .width(1920)
      .height(540)
      .gravity(autoGravity())
  )
  .delivery(format(autoFormat()))
  .delivery(quality(autoQuality()));
```

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

new CloudinaryImage("campaigns/summer_launch")
  .resize(
    auto()
      .width(1920)
      .height(540)
      .gravity(autoGravity())
  )
  .delivery(format(autoFormat()))
  .delivery(quality(autoQuality()));
```

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

new CloudinaryImage("campaigns/summer_launch")
  .resize(
    auto()
      .width(1920)
      .height(540)
      .gravity(autoGravity())
  )
  .delivery(format(autoFormat()))
  .delivery(quality(autoQuality()));
```

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

new CloudinaryImage("campaigns/summer_launch")
  .resize(
    auto()
      .width(1920)
      .height(540)
      .gravity(autoGravity())
  )
  .delivery(format(autoFormat()))
  .delivery(quality(autoQuality()));
```

```python
CloudinaryImage("campaigns/summer_launch").image(transformation=[
  {'gravity': "auto", 'height': 540, 'width': 1920, 'crop': "auto"},
  {'quality': "auto"}
  ])
```

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

(new ImageTag('campaigns/summer_launch'))
	->resize(Resize::auto()->width(1920)
->height(540)
	->gravity(
	Gravity::autoGravity())
	)
	->delivery(Delivery::format(
	Format::auto()))
	->delivery(Delivery::quality(
	Quality::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .gravity("auto").height(540).width(1920).crop("auto").chain()
  .quality("auto")).imageTag("campaigns/summer_launch");
```

```ruby
cl_image_tag("campaigns/summer_launch", transformation: [
  {gravity: "auto", height: 540, width: 1920, crop: "auto"},
  {quality: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("auto").Height(540).Width(1920).Crop("auto").Chain()
  .Quality("auto")).BuildImageTag("campaigns/summer_launch")
```

```dart
cloudinary.image('campaigns/summer_launch').transformation(Transformation()
	.resize(Resize.auto().width(1920)
.height(540)
	.gravity(
	Gravity.autoGravity())
	)
	.delivery(Delivery.format(
	Format.auto()))
	.delivery(Delivery.quality(
	Quality.auto())));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("auto").setHeight(540).setWidth(1920).setCrop("auto").chain()
  .setQuality("auto")).generate("campaigns/summer_launch")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .gravity("auto").height(540).width(1920).crop("auto").chain()
  .quality("auto")).generate("campaigns/summer_launch");
```

```flutter
cloudinary.image('campaigns/summer_launch').transformation(Transformation()
	.resize(Resize.auto().width(1920)
.height(540)
	.gravity(
	Gravity.autoGravity())
	)
	.delivery(Delivery.format(
	Format.auto()))
	.delivery(Delivery.quality(
	Quality.auto())));
```

```kotlin
cloudinary.image {
	publicId("campaigns/summer_launch")
	 resize(Resize.auto() { width(1920)
 height(540)
	 gravity(
	Gravity.autoGravity())
	 })
	 delivery(Delivery.format(
	Format.auto()))
	 delivery(Delivery.quality(
	Quality.auto())) 
}.generate()
```

```jquery
$.cloudinary.image("campaigns/summer_launch", {transformation: [
  {gravity: "auto", height: 540, width: 1920, crop: "auto"},
  {quality: "auto"}
  ]})
```

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

new CloudinaryImage("campaigns/summer_launch")
  .resize(
    auto()
      .width(1920)
      .height(540)
      .gravity(autoGravity())
  )
  .delivery(format(autoFormat()))
  .delivery(quality(autoQuality()));
```

&nbsp;
[Learn more](image_generation_addon) | [Jump to the Image Generation UI](https://console.cloudinary.com/app/image/generation)

### New Console Studio UI for image transformations

The new Console [Studio](https://console.cloudinary.com/app/image/studio) is now available on all plans.

Studio provides a visual workspace for building and previewing image transformations, refining AI-generated edits, and creating reusable named transformation templates. You can apply transformations to one or multiple images, save the results as new assets or overwrite existing assets, and create or refine edits as needed.

![New Studio](https://cloudinary-res.cloudinary.com/image/upload/f_auto/q_auto/bo_1px_solid_grey/docs/studio/studio_initial.png "thumb: w_650,dpr_2, width:650, with_code:false, with_url:false")

Learn more: [Studio overview](dam_editing_and_transformations#studio) | [Creating named transformations with Studio](named_transformations#create_a_named_transformation_in_the_console_studio)

> **NOTE**:
>
> As of June 2026, the new Studio is the Console interface for managing **image** transformations. The [Transformation Builder](https://console.cloudinary.com/app/image/transformation_builder) is still used as the interface for managing video transformations.

### Dynamic download filenames using variables

The [fl_attachment](transformation_reference#fl_attachment) flag now accepts a [user-defined variable](user_defined_variables) as the filename value, so you can name downloaded files dynamically based on each asset's metadata. Assign the variable a value from the asset's structured metadata (`md:!<external_id>!`) or contextual metadata (`ctx:!<key_name>!`) in an earlier transformation component, then reference it as the attachment filename.

**Example: Name the downloaded file based on the asset's contextual metadata**

The `$n` variable takes the value of the image's `productType` contextual metadata key, which is `shoes`, so clicking the URL link downloads the file as `shoes.jpg`:

![Download an image with a dynamic filename](https://res.cloudinary.com/demo/image/upload/$n_ctx:!productType!/fl_attachment:$n/sunset_shoes.jpg "with_image:false")

```nodejs
cloudinary.image("sunset_shoes.jpg", {transformation: [
  {variables: [["$n", "ctx:!productType!"]]},
  {flags: "attachment:$n"}
  ]})
```

```react
import { setFromContext } from "@cloudinary/url-gen/actions/variable";
import { attachment } from "@cloudinary/url-gen/qualifiers/flag";

new CloudinaryImage("sunset_shoes.jpg")
  .addVariable(setFromContext("n", "productType"))
  .addFlag(attachment("$n"));
```

```vue
import { setFromContext } from "@cloudinary/url-gen/actions/variable";
import { attachment } from "@cloudinary/url-gen/qualifiers/flag";

new CloudinaryImage("sunset_shoes.jpg")
  .addVariable(setFromContext("n", "productType"))
  .addFlag(attachment("$n"));
```

```angular
import { setFromContext } from "@cloudinary/url-gen/actions/variable";
import { attachment } from "@cloudinary/url-gen/qualifiers/flag";

new CloudinaryImage("sunset_shoes.jpg")
  .addVariable(setFromContext("n", "productType"))
  .addFlag(attachment("$n"));
```

```js
import { setFromContext } from "@cloudinary/url-gen/actions/variable";
import { attachment } from "@cloudinary/url-gen/qualifiers/flag";

new CloudinaryImage("sunset_shoes.jpg")
  .addVariable(setFromContext("n", "productType"))
  .addFlag(attachment("$n"));
```

```python
CloudinaryImage("sunset_shoes.jpg").image(transformation=[
  {'variables': [["$n", "ctx:!productType!"]]},
  {'flags': "attachment:$n"}
  ])
```

```php
use Cloudinary\Transformation\Variable;
use Cloudinary\Transformation\Flag;

(new ImageTag('sunset_shoes.jpg'))
	->addVariable(Variable::setFromContext("n","productType"))
	->addFlag(
	Flag::attachment("$n"));
```

```java
cloudinary.url().transformation(new Transformation()
  .variables(variable("$n","ctx:!productType!")).chain()
  .flags("attachment:$n")).imageTag("sunset_shoes.jpg");
```

```ruby
cl_image_tag("sunset_shoes.jpg", transformation: [
  {variables: [["$n", "ctx:!productType!"]]},
  {flags: "attachment:$n"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Variables("$n", ctx:!productType!).Chain()
  .Flags("attachment:$n")).BuildImageTag("sunset_shoes.jpg")
```

```dart
cloudinary.image('sunset_shoes.jpg').transformation(Transformation()
	.addVariable(Variable.setFromContext("n","productType"))
	.addFlag(
	Flag.attachment("$n")));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .chain()
  .setFlags("attachment:$n")).generate("sunset_shoes.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .variables(variable("$n","ctx:!productType!")).chain()
  .flags("attachment:$n")).generate("sunset_shoes.jpg");
```

```flutter
cloudinary.image('sunset_shoes.jpg').transformation(Transformation()
	.addVariable(Variable.setFromContext("n","productType"))
	.addFlag(
	Flag.attachment("$n")));
```

```kotlin
cloudinary.image {
	publicId("sunset_shoes.jpg")
	 addVariable(Variable.setFromContext("n","productType"))
	 addFlag(
	Flag.attachment("\$n")) 
}.generate()
```

```jquery
$.cloudinary.image("sunset_shoes.jpg", {transformation: [
  {variables: [["$n", "ctx:!productType!"]]},
  {flags: "attachment:$n"}
  ]})
```

```react_native
import { setFromContext } from "@cloudinary/url-gen/actions/variable";
import { attachment } from "@cloudinary/url-gen/qualifiers/flag";

new CloudinaryImage("sunset_shoes.jpg")
  .addVariable(setFromContext("n", "productType"))
  .addFlag(attachment("$n"));
```

[Learn more](transformation_reference#fl_attachment)

### Our image optimization technology is now patented!

We're proud to announce that Cloudinary has been granted U.S. Patent No. 12,602,838 for the image optimization technology behind the latest generation of [`q_auto`](image_optimization#automatic_quality_selection_q_auto). This milestone recognizes the innovation that lets Cloudinary intelligently balance visual quality and file size for every image, and cements our leadership in media optimization.

If you aren't already applying `q_auto` (or better yet, `f_auto/q_auto`) to every asset you deliver to get the best format and quality optimizations, no time like the present!

[Learn more about automatic quality (q_auto)](image_optimization#automatic_quality_selection_q_auto)

## Cloudinary Video

### Custom fonts for video subtitles

The `l_subtitles` transformation now accepts custom fonts in addition to universally available font names. You can brand subtitles with `.ttf`, `.otf`, or `.woff2` font files uploaded to your product environment as [raw](upload_parameters#uploading_non_media_files_as_raw_files), [authenticated](upload_parameters#authenticated_assets) assets. 

**Example: Embed subtitles using the custom `Alex Brush.ttf` font at size 40, in white text on a black background**

![Video with subtitles using a custom font](https://res.cloudinary.com/demo/video/upload/b_black,co_white,l_subtitles:Alex%20Brush.ttf_40:outdoors.vtt/fl_layer_apply/docs/rocky-mountains.mp4 "thumb: h_350")

```nodejs
cloudinary.video("docs/rocky-mountains", {transformation: [
  {background: "black", color: "white", overlay: {font_family: "ttf", font_size: 40, resource_type: "subtitles", public_id: "outdoors.vtt"}},
  {flags: "layer_apply"}
  ]})
```

```react
import { source } from "@cloudinary/url-gen/actions/overlay";
import { subtitles } from "@cloudinary/url-gen/qualifiers/source";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";

new CloudinaryVideo("docs/rocky-mountains.mp4").overlay(
  source(
    subtitles("outdoors.vtt")
      .textStyle(new TextStyle("Alex Brush.ttf", 40))
      .textColor("white")
      .backgroundColor("black")
  )
);
```

```vue
import { source } from "@cloudinary/url-gen/actions/overlay";
import { subtitles } from "@cloudinary/url-gen/qualifiers/source";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";

new CloudinaryVideo("docs/rocky-mountains.mp4").overlay(
  source(
    subtitles("outdoors.vtt")
      .textStyle(new TextStyle("Alex Brush.ttf", 40))
      .textColor("white")
      .backgroundColor("black")
  )
);
```

```angular
import { source } from "@cloudinary/url-gen/actions/overlay";
import { subtitles } from "@cloudinary/url-gen/qualifiers/source";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";

new CloudinaryVideo("docs/rocky-mountains.mp4").overlay(
  source(
    subtitles("outdoors.vtt")
      .textStyle(new TextStyle("Alex Brush.ttf", 40))
      .textColor("white")
      .backgroundColor("black")
  )
);
```

```js
import { source } from "@cloudinary/url-gen/actions/overlay";
import { subtitles } from "@cloudinary/url-gen/qualifiers/source";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";

new CloudinaryVideo("docs/rocky-mountains.mp4").overlay(
  source(
    subtitles("outdoors.vtt")
      .textStyle(new TextStyle("Alex Brush.ttf", 40))
      .textColor("white")
      .backgroundColor("black")
  )
);
```

```python
CloudinaryVideo("docs/rocky-mountains").video(transformation=[
  {'background': "black", 'color': "white", 'overlay': {'font_family': "ttf", 'font_size': 40, 'resource_type': "subtitles", 'public_id': "outdoors.vtt"}},
  {'flags': "layer_apply"}
  ])
```

```php
use Cloudinary\Transformation\Overlay;
use Cloudinary\Transformation\Source;
use Cloudinary\Transformation\TextStyle;

(new VideoTag('docs/rocky-mountains.mp4'))
	->overlay(Overlay::source(
	Source::subtitles("outdoors.vtt")
	->textStyle((new TextStyle("Alex Brush.ttf",40)))
	->textColor(Color::WHITE)
	->backgroundColor(Color::BLACK)
	));
```

```java
cloudinary.url().transformation(new Transformation()
  .background("black").color("white").overlay(new SubtitlesLayer().fontFamily("ttf").fontSize(40).publicId("outdoors.vtt")).chain()
  .flags("layer_apply")).videoTag("docs/rocky-mountains");
```

```ruby
cl_video_tag("docs/rocky-mountains", transformation: [
  {background: "black", color: "white", overlay: {font_family: "ttf", font_size: 40, resource_type: "subtitles", public_id: "outdoors.vtt"}},
  {flags: "layer_apply"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Background("black").Color("white").Overlay(new SubtitlesLayer().FontFamily("ttf").FontSize(40).PublicId("outdoors.vtt")).Chain()
  .Flags("layer_apply")).BuildVideoTag("docs/rocky-mountains")
```

```dart
cloudinary.video('docs/rocky-mountains.mp4').transformation(Transformation()
	.overlay(Overlay.source(
	Source.subtitles("outdoors.vtt")
	.textStyle(TextStyle("Alex Brush.ttf",40))
	.textColor(Color.WHITE)
	.backgroundColor(Color.BLACK)
	)));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setBackground("black").setColor("white").setOverlay("subtitles:Alex%20Brush.ttf_40:outdoors.vtt").chain()
  .setFlags("layer_apply")).generate("docs/rocky-mountains.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .background("black").color("white").overlay(new SubtitlesLayer().fontFamily("ttf").fontSize(40).publicId("outdoors.vtt")).chain()
  .flags("layer_apply")).resourceType("video").generate("docs/rocky-mountains.mp4");
```

```flutter
cloudinary.video('docs/rocky-mountains.mp4').transformation(Transformation()
	.overlay(Overlay.source(
	Source.subtitles("outdoors.vtt")
	.textStyle(TextStyle("Alex Brush.ttf",40))
	.textColor(Color.WHITE)
	.backgroundColor(Color.BLACK)
	)));
```

```kotlin
cloudinary.video {
	publicId("docs/rocky-mountains.mp4")
	 overlay(Overlay.source(
	Source.subtitles("outdoors.vtt") {
	 textStyle(TextStyle("Alex Brush.ttf",40))
	 textColor(Color.WHITE)
	 backgroundColor(Color.BLACK)
	 })) 
}.generate()
```

```jquery
$.cloudinary.video("docs/rocky-mountains", {transformation: [
  {background: "black", color: "white", overlay: new cloudinary.SubtitlesLayer().fontFamily("ttf").fontSize(40).publicId("outdoors.vtt")},
  {flags: "layer_apply"}
  ]})
```

```react_native
import { source } from "@cloudinary/url-gen/actions/overlay";
import { subtitles } from "@cloudinary/url-gen/qualifiers/source";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";

new CloudinaryVideo("docs/rocky-mountains.mp4").overlay(
  source(
    subtitles("outdoors.vtt")
      .textStyle(new TextStyle("Alex Brush.ttf", 40))
      .textColor("white")
      .backgroundColor("black")
  )
);
``` 

[Learn more](video_layers#custom_fonts_for_subtitles)

## Agentic skills and IDE tooling

### New Cloudinary skill for Next.js

Building with Cloudinary in a Next.js app? Our new **cloudinary-next** skill helps your AI agent get it right the first time. It encodes Cloudinary's recommended Next.js patterns, so the code your agent generates follows best practices and patterns from the start, using [Cloudinary Next.js SDK](nextjs_integration) components and helpers like `CldImage`, `CldVideoPlayer`, and `CldUploadWidget`.

The result is correctly configured, reliable Next.js integrations, with clean Server and Client Component boundaries, server-side uploads and deletes, signed uploads, responsive images, overlays, OG social images, and more.

Just run the `npx` command below to install:

```bash
npx skills add cloudinary-devs/skills
```

[Learn more about Cloudinary agentic skills](cloudinary_llm_mcp#cloudinary_skills)

### Get the latest updates on all skills

We've recently leveled up our existing **cloudinary-docs**, **cloudinary-transformations**, and **cloudinary-react** skills. Guided by research and automated testing against real customer use cases, we refined each one to improve its performance and the quality of the results it produces.

If you've already installed any of these skills, we recommend that you re-run the `npx` command to pick up the latest improvements:

```bash
npx skills add cloudinary-devs/skills
```

> **TIP**: Each Cloudinary `SKILL.md` file includes a `version` value in its metadata. To check whether you're on the latest at any time, compare the versions of your installed skills against those in the [Cloudinary Skills repo](https://github.com/cloudinary-devs/skills).

[Learn more about Cloudinary agentic skills](cloudinary_llm_mcp#cloudinary_skills)

### Cloudinary VS Code Extension 1.0 is here

The [Cloudinary VS Code Extension](cloudinary_vscode_extension) is now GA, with a batch of new capabilities shaped by Beta feedback. 

Manage your assets and wire up Cloudinary's AI tooling without leaving your editor, in VS Code or any VS Code-based IDE (Cursor, Antigravity, Windsurf, and more).

**What's new in 1.0**: 

* **Docs AI assistant**: Ask questions about Cloudinary right in your editor and get answers drawn from the docs, with source citations and conversation history.
* **Home dashboard**: A redesigned central panel with quick actions, Media Library search, the Docs AI assistant, and AI tool configuration.
* **Configure AI tools**: Set up Cloudinary agent skills and MCP servers for your AI coding assistant in one step, at project or global scope.
* **Rebuilt media library**: A faster asset explorer with progressive loading, search, filtering, and sorting.

**Watch it in action:**

![Cloudinary VS Code Extension](https://cloudinary-res.cloudinary.com/video/upload/f_auto/q_auto/v1783427465/kuzfjl95kyrcsgn3axh4.mp4 "thumb:c_scale,w_600/dpr_2, with_code:false, with_url:false, width:600")

Install the extension from the Extensions tab of your IDE or from the marketplace: 

* [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=cloudinary.cloudinary)
* [Open VSX Registry](https://open-vsx.org/extension/cloudinary/cloudinary) for VS Code-based IDEs such as Cursor, Antigravity, etc.

[Learn more](cloudinary_vscode_extension)

## Asset management and upload

### Updated backup experience in Console Settings

The [Backup](https://console.cloudinary.com/app/settings/backup) page in the Console Settings lets you enable automatic backup and configure where your backups are stored. You can now also back up existing assets without leaving the page. 

Every job run in your product environment now appears in the **Previous backup jobs for existing assets** table, where you can check its process ID, creation timestamp, and current status to confirm it completed successfully and keep a record of when backups were run.

![backup settings](https://cloudinary-res.cloudinary.com/video/upload/so_17/c_crop,g_south,w_2000,h_400,y_100/f_auto/q_auto/bo_1px_solid_grey/v1782123101/enable_backup_easily.jpg "thumb: w_600,dpr_2, width:600, with_code:false, with_url:false")

[Learn more](backups_and_version_management)

## Account management

### Create and manage OAuth apps yourself in the Console

Setting up OAuth 2.0 access to Cloudinary's APIs no longer requires a support ticket. You can now create and manage your own **OAuth apps** directly in the Console, under **Settings > Developers > OAuth Apps**.

Create an app, generate a client secret (and rotate it whenever you need to), select the scopes your app needs, and add the redirect URIs for your integration. Deleting an app revokes its access, with no need to involve Cloudinary support.

![The new OAuth Apps page in the Console](https://cloudinary-res.cloudinary.com/image/upload/f_auto/q_auto/bo_1px_solid_grey/v1781720216/docs/accounts_ui/oauth-apps-empty-state.png "thumb: w_540,dpr_2, width:540, with_code:false, with_url:false")

[Learn more](using_oauth_to_access_cloudinary_apis#create_and_manage_oauth_apps)

### Account creation API for agents

AI agents can now create a Cloudinary account programmatically with the new [account creation API for agents](agent_account_provisioning). The agent sends a single request and receives the account details and credentials, which work after a human verifies the email to activate the account. This API is in Early Access.

**Example: Create an account with a single request**

```curl
curl -X POST https://api.cloudinary.com/v1_1/provisioning/agents/accounts \
  -H "Content-Type: application/json" \
  -d '{
    "email": "builder@example.com",
    "agent_framework": "langchain",
    "agent_llm_model": "claude-opus-4-8",
    "agent_goal": "Add image optimization and uploads to a web app",
    "sdk_framework": "nodejs"
  }'
```

The response includes the new account details, one `product_environments` entry with the cloud name and API credentials, and a `guidance` block the agent can use to walk the user through email verification and SDK setup.

[Learn more](agent_account_provisioning)

## Docs and demo apps

### Download transcript button for video tutorials

Documentation pages with video tutorials now include a **Download Transcript** button below the video player. Select it to download the video transcript as a VTT file, which you can use with screen readers, translation tools, or any VTT-compatible application.

[Check out all the Image & Video API video tutorials](tutorial_screencasts)

## Announcements

### Cloudinary Moderation now includes Video Moderation!

Video Moderation extends Cloudinary Moderation beyond images, helping teams automate video review at scale while reducing manual effort.

Every video that enters your pipeline, from marketplace sellers, agency partners, creators, or end users, can be evaluated in near-real time against your brand, safety, and compliance rules, then automatically approved, routed for human review, or rejected.

**What's included?**

* Content detection: detect selected objects, scenes, or concepts across video frames
* Video text analysis: moderate on-screen text in videos
* Video transcript analysis: moderate spoken content using generated transcripts
* Metadata validation: verify that on-screen text matches metadata values, for example, confirming that the correct product appears in the video

[Learn more](https://cloudinary.com/documentation/cloudinary_moderation)

