home / skills / vm0-ai / vm0-skills / cloudinary

cloudinary skill

/cloudinary

This skill helps you upload and transform media via Cloudinary, delivering optimized images and videos through CDN with easy URL transformations.

npx playbooks add skill vm0-ai/vm0-skills --skill cloudinary

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.8 KB
---
name: cloudinary
description: Upload images and videos to Cloudinary with CDN delivery and transformations. Use this skill for media hosting, optimization, resizing, format conversion, and video concatenation.
vm0_secrets:
  - CLOUDINARY_API_KEY
  - CLOUDINARY_API_SECRET
vm0_vars:
  - CLOUDINARY_CLOUD_NAME
---

# Cloudinary Media Hosting

Cloudinary provides image and video hosting with CDN delivery, automatic optimization, and on-the-fly transformations.

## When to Use

- Upload images with automatic optimization
- Upload videos with CDN delivery
- Get CDN-delivered media URLs
- Apply transformations (resize, crop, format conversion)
- Concatenate/splice multiple videos
- Host media for production applications

## Prerequisites

Set the following environment variables:

```bash
export CLOUDINARY_CLOUD_NAME=your_cloud_name
export CLOUDINARY_API_KEY=your_api_key
export CLOUDINARY_API_SECRET=your_api_secret
```

Get credentials from: https://console.cloudinary.com/settings/api-keys


> **Important:** When using `$VAR` in a command that pipes to another command, wrap the command containing `$VAR` in `bash -c '...'`. Due to a Claude Code bug, environment variables are silently cleared when pipes are used directly.
> ```bash
> bash -c 'curl -s "https://api.example.com" -H "Authorization: Bearer $API_KEY"'
> ```

## How to Use

### Method 1: Unsigned Upload (Simpler)

First, create an unsigned upload preset in Cloudinary Console:
Settings > Upload > Upload presets > Add upload preset > Signing Mode: Unsigned

```bash
curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/image/upload" -F "file=@/path/to/image.png" -F "upload_preset=your_preset_name"
```

### Method 2: Signed Upload

Generate signature and upload:

```bash
# Generate timestamp
TIMESTAMP=$(date +%s)

# Generate signature (alphabetical order of params)
SIGNATURE=$(bash -c 'echo -n "timestamp=$TIMESTAMP$CLOUDINARY_API_SECRET" | sha1sum | cut -d" " -f1')

# Upload
curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/image/upload" -F "file=@/path/to/image.png" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload from URL

```bash
TIMESTAMP=$(date +%s)
SIGNATURE=$(bash -c 'echo -n "timestamp=$TIMESTAMP$CLOUDINARY_API_SECRET" | sha1sum | cut -d" " -f1')

curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/image/upload" -F "file=https://example.com/image.png" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload Video

```bash
TIMESTAMP=$(date +%s)
SIGNATURE=$(bash -c 'echo -n "timestamp=$TIMESTAMP$CLOUDINARY_API_SECRET" | sha1sum | cut -d" " -f1')

curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/video/upload" -F "file=@/path/to/video.mp4" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload Video with Custom Public ID

```bash
TIMESTAMP=$(date +%s)
PUBLIC_ID="my-videos/clip1"
SIGNATURE=$(bash -c 'echo -n "public_id=$PUBLIC_ID&timestamp=$TIMESTAMP$CLOUDINARY_API_SECRET" | sha1sum | cut -d" " -f1')

curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/video/upload" -F "file=@/path/to/video.mp4" -F "public_id=$PUBLIC_ID" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload Video from URL

```bash
TIMESTAMP=$(date +%s)
PUBLIC_ID="my-videos/clip1"
SIGNATURE=$(bash -c 'echo -n "public_id=$PUBLIC_ID&timestamp=$TIMESTAMP$CLOUDINARY_API_SECRET" | sha1sum | cut -d" " -f1')

curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/video/upload" -F "file=https://example.com/video.mp4" -F "public_id=$PUBLIC_ID" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### With Custom Public ID

```bash
TIMESTAMP=$(date +%s)
PUBLIC_ID="my-folder/my-image"
SIGNATURE=$(bash -c 'echo -n "public_id=$PUBLIC_ID&timestamp=$TIMESTAMP$CLOUDINARY_API_SECRET" | sha1sum | cut -d" " -f1')

curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/image/upload" -F "file=@/path/to/image.png" -F "public_id=$PUBLIC_ID" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

## Response

```json
{
  "public_id": "sample",
  "secure_url": "https://res.cloudinary.com/demo/image/upload/v1234567890/sample.png",
  "url": "http://res.cloudinary.com/demo/image/upload/v1234567890/sample.png",
  "format": "png",
  "width": 800,
  "height": 600
}
```

Key field: `secure_url` - Use this in Markdown: `![img](https://res.cloudinary.com/...)`

## URL Transformations

Cloudinary URLs support on-the-fly transformations:

```
https://res.cloudinary.com/{cloud_name}/image/upload/{transformations}/{public_id}.{format}
```

Examples:
```
# Resize to 300x200
.../image/upload/w_300,h_200/sample.png

# Auto format and quality
.../image/upload/f_auto,q_auto/sample.png

# Crop to square
.../image/upload/w_200,h_200,c_fill/sample.png

# Combine transformations
.../image/upload/w_400,h_300,c_fill,f_auto,q_auto/sample.png
```

## Video Concatenation (Splice)

Concatenate videos using URL transformations with `l_video:` (overlay) and `fl_splice` flag.

### Basic Concatenation

Append `clip2` to the end of `clip1`:

```
https://res.cloudinary.com/{cloud_name}/video/upload/l_video:clip2,fl_splice/fl_layer_apply/clip1.mp4
```

### Concatenate Multiple Videos

Append `clip2` and `clip3` to `clip1`:

```
https://res.cloudinary.com/{cloud_name}/video/upload/l_video:clip2,fl_splice/fl_layer_apply/l_video:clip3,fl_splice/fl_layer_apply/clip1.mp4
```

### With Uniform Size

Resize all videos to same dimensions:

```
https://res.cloudinary.com/{cloud_name}/video/upload/w_640,h_360,c_fill/l_video:clip2,fl_splice,w_640,h_360,c_fill/fl_layer_apply/clip1.mp4
```

### With Fade Transition

Add fade out (-1000ms) on first video and fade in (1000ms) on second:

```
https://res.cloudinary.com/{cloud_name}/video/upload/w_640,h_360,c_fill,e_fade:-1000/l_video:clip2,fl_splice,e_fade:1000,w_640,h_360,c_fill/fl_layer_apply/clip1.mp4
```

### Add Image as Intro (3 seconds)

Prepend an image as intro:

```
https://res.cloudinary.com/{cloud_name}/video/upload/l_intro_image,fl_splice,du_3/so_0,fl_layer_apply/clip1.mp4
```

### Limitations

- URL length limit (~2000 chars) restricts number of videos
- First request triggers server-side processing (slow)
- For many videos (10+), consider using ffmpeg or dedicated video APIs

## Delete Media

```bash
TIMESTAMP=$(date +%s)
PUBLIC_ID="<your-public-id>"
SIGNATURE=$(bash -c 'echo -n "public_id=$PUBLIC_ID&timestamp=$TIMESTAMP$CLOUDINARY_API_SECRET" | sha1sum | cut -d" " -f1')

# Delete image
curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/image/destroy" -F "public_id=$PUBLIC_ID" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"

# Delete video
curl -X POST "https://api.cloudinary.com/v1_1/<your-cloud-name>/video/destroy" -F "public_id=$PUBLIC_ID" -F "api_key=$CLOUDINARY_API_KEY" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

## Free Tier Limits

- 25 credits/month
- ~25,000 transformations or ~25GB storage/bandwidth
- Sufficient for personal projects

## Guidelines

1. **Use unsigned presets** for simpler uploads when security isn't critical
2. **Signature order**: Parameters must be alphabetically sorted when generating signature
3. **Auto optimization**: Add `f_auto,q_auto` to URLs for automatic format/quality
4. **Folders**: Use `public_id="folder/subfolder/name"` to organize media
5. **Video concatenation**: Keep URLs short; for 10+ videos use external tools

## API Reference

- Image Upload: https://cloudinary.com/documentation/image_upload_api_reference
- Video Upload: https://cloudinary.com/documentation/video_upload_api_reference
- Video Concatenation: https://cloudinary.com/documentation/video_trimming_and_concatenating
- Console: https://console.cloudinary.com/
- Transformation Reference: https://cloudinary.com/documentation/transformation_reference

Overview

This skill uploads images and videos to Cloudinary and delivers them via CDN with on-the-fly transformations. It supports signed and unsigned uploads, URL-based uploads, video concatenation, automatic format/quality optimization, and media deletion. Use it to host, optimize, resize, convert formats, and stitch videos without managing your own CDN.

How this skill works

The skill uses Cloudinary HTTP APIs to perform uploads and deletions and generates CDN-ready secure URLs for delivered assets. Signed uploads require a timestamp and SHA1 signature built from your API secret; unsigned uploads use an upload preset. Transformations are encoded directly into the Cloudinary delivery URL to resize, crop, change format, adjust quality, or concatenate video clips on demand.

When to use it

  • Host images and videos for web or mobile apps with CDN delivery
  • Automatically optimize images (f_auto,q_auto) for performance
  • Resize/crop or convert formats via URL transformations
  • Upload large assets or import media from external URLs
  • Concatenate or splice multiple video clips without pre-processing

Best practices

  • Set CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, and CLOUDINARY_API_SECRET as environment variables
  • Use unsigned upload presets for client-side uploads when security needs are low
  • Alphabetically sort parameters when generating signed upload signatures
  • Add f_auto,q_auto to delivery URLs to enable auto format and quality
  • Keep transformation URLs short; for many clips (10+) use ffmpeg or a dedicated video pipeline

Example use cases

  • Upload product photos and serve responsive images with width and quality transforms
  • Ingest user-generated video clips, concatenate them into a short highlight reel, and serve via CDN
  • Import an external image or video URL directly into Cloudinary for central hosting
  • Store versioned media with folder-style public IDs (folder/subfolder/name) and delete old assets programmatically
  • Convert uploads to modern formats (AVIF/WEBP/MP4) automatically with f_auto,q_auto

FAQ

Do I need to use signed uploads?

Signed uploads are recommended for server-side security. Use unsigned presets only when you accept the security trade-offs for easier client uploads.

How do I concatenate many videos?

Use URL-based splice with l_video and fl_splice for small numbers. For 10+ videos, use ffmpeg or a job-based API to avoid URL length limits and slow first-request processing.

Which field returns the CDN URL?

Use the secure_url field from the upload response for reliable HTTPS delivery and embedding.