cloudinary

$npx mdskill add vm0-ai/vm0-skills/cloudinary

Upload and transform images or videos using Cloudinary API.

  • Handles image and video asset management tasks.
  • Integrates with Cloudinary API for secure uploads.
  • Executes requests based on user media asset commands.
  • Returns processed media files or upload confirmation.
SKILL.md
.github/skills/cloudinaryView on GitHub ↗
---
name: cloudinary
description: Cloudinary API for image/video management. Use when user mentions "Cloudinary",
  "upload image", "transform image", or media assets.
---

## Troubleshooting

If requests fail, run `zero doctor check-connector --env-name CLOUDINARY_TOKEN` or `zero doctor check-connector --url https://api.cloudinary.com/v1_1/your-cloud-name/image/upload --method POST`

## 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=$(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_TOKEN" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload from URL

```bash
TIMESTAMP=$(date +%s)
SIGNATURE=$(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_TOKEN" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload Video

```bash
TIMESTAMP=$(date +%s)
SIGNATURE=$(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_TOKEN" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload Video with Custom Public ID

```bash
TIMESTAMP=$(date +%s)
PUBLIC_ID="my-videos/clip1"
SIGNATURE=$(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_TOKEN" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### Upload Video from URL

```bash
TIMESTAMP=$(date +%s)
PUBLIC_ID="my-videos/clip1"
SIGNATURE=$(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_TOKEN" -F "timestamp=$TIMESTAMP" -F "signature=$SIGNATURE"
```

### With Custom Public ID

```bash
TIMESTAMP=$(date +%s)
PUBLIC_ID="my-folder/my-image"
SIGNATURE=$(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_TOKEN" -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=$(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_TOKEN" -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_TOKEN" -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
More from vm0-ai/vm0-skills