Manages images and videos with Cloudinary including upload, transformation, and CDN delivery. Use when building media-rich applications requiring resize, crop, format conversion, and optimization.
Upload, transform, and optimize images and videos using Cloudinary. Use when your app needs to resize, crop, apply effects, or generate CDN URLs for media assets.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Image and video management platform with upload, transformation, optimization, and global CDN delivery.
npm install cloudinary
import { v2 as cloudinary } from 'cloudinary';
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
secure: true
});
// From local file
const result = await cloudinary.uploader.upload('./image.jpg', {
public_id: 'my-image', // Optional custom ID
folder: 'products', // Optional folder
});
console.log(result.secure_url);
// https://res.cloudinary.com/cloud/image/upload/v1234/products/my-image.jpg
// From URL
const result = await cloudinary.uploader.upload(
'https://example.com/image.jpg',
{ folder: 'external' }
);
// From base64
const result = await cloudinary.uploader.upload(
'data:image/png;base64,iVBORw0KGgo...',
{ folder: 'uploads' }
);
const result = await cloudinary.uploader.upload('./image.jpg', {
public_id: 'my-image',
folder: 'products',
// Transformations on upload
transformation: [
{ width: 1000, height: 1000, crop: 'limit' },
{ quality: 'auto', fetch_format: 'auto' }
],
// Eager transformations (pre-generate)
eager: [
{ width: 200, height: 200, crop: 'thumb', gravity: 'face' },
{ width: 800, crop: 'scale' }
],
// Tags for organization
tags: ['product', 'shoes'],
// Metadata
context: 'caption=Nike Shoes|alt=Running shoes',
// Overwrite existing
overwrite: true,
invalidate: true,
// Resource type
resource_type: 'image', // 'image', 'video', 'raw', 'auto'
// Access control
type: 'upload', // 'upload', 'private', 'authenticated'
});
// For files > 100MB
const result = await cloudinary.uploader.upload_large('./large-video.mp4', {
resource_type: 'video',
chunk_size: 6000000, // 6MB chunks
});
Build URLs with on-the-fly transformations.
// Using cloudinary.url()
const url = cloudinary.url('products/my-image', {
width: 400,
height: 300,
crop: 'fill',
gravity: 'auto',
quality: 'auto',
fetch_format: 'auto',
});
// https://res.cloudinary.com/cloud/image/upload/w_400,h_300,c_fill,g_auto,q_auto,f_auto/products/my-image
// Manual URL construction
const baseUrl = `https://res.cloudinary.com/${cloudName}/image/upload`;
const transformations = 'w_400,h_300,c_fill,g_auto,q_auto,f_auto';
const publicId = 'products/my-image';
const url = `${baseUrl}/${transformations}/${publicId}`;
{
width: 400,
height: 300,
crop: 'fill', // fill, fit, scale, thumb, crop, pad
gravity: 'auto', // auto, face, center, north, south, east, west
aspect_ratio: '16:9',
}
| Mode | Description |
|---|---|
fill | Fill dimensions, crop excess |
fit | Fit within dimensions, maintain ratio |
scale | Scale to dimensions (may distort) |
thumb | Thumbnail with smart crop |
crop | Crop from specified area |
pad | Add padding to fit dimensions |
limit | Like fit, but never upscale |
{
quality: 'auto', // auto, auto:low, auto:good, auto:best, 1-100
fetch_format: 'auto', // auto, webp, avif, jpg, png
}
{
effect: 'blur:500',
effect: 'grayscale',
effect: 'sepia',
effect: 'brightness:30',
effect: 'contrast:50',
effect: 'saturation:70',
effect: 'sharpen',
effect: 'vignette',
effect: 'art:athena', // Artistic filters
}
{
crop: 'thumb',
gravity: 'face', // Center on face
width: 200,
height: 200,
}
// Multiple faces
{
crop: 'thumb',
gravity: 'faces',
width: 400,
height: 300,
}
// Text overlay
{
overlay: {
font_family: 'Arial',
font_size: 40,
text: 'Hello World'
},
gravity: 'south',
y: 20,
color: 'white',
}
// Image overlay (watermark)
{
overlay: 'logo',
gravity: 'south_east',
x: 10,
y: 10,
width: 100,
opacity: 50,
}
const url = cloudinary.url('products/shoe', {
transformation: [
// First: resize
{ width: 800, height: 600, crop: 'fill' },
// Then: apply effect
{ effect: 'improve' },
// Finally: optimize
{ quality: 'auto', fetch_format: 'auto' }
]
});
npm install @cloudinary/react @cloudinary/url-gen
import { Cloudinary } from '@cloudinary/url-gen';
import { AdvancedImage } from '@cloudinary/react';
import { fill } from '@cloudinary/url-gen/actions/resize';
import { autoGravity } from '@cloudinary/url-gen/qualifiers/gravity';
import { format, quality } from '@cloudinary/url-gen/actions/delivery';
import { auto } from '@cloudinary/url-gen/qualifiers/format';
// Configure
const cld = new Cloudinary({
cloud: { cloudName: 'your-cloud-name' }
});
function ProductImage({ publicId }) {
const image = cld
.image(publicId)
.resize(fill().width(400).height(300).gravity(autoGravity()))
.delivery(format(auto()))
.delivery(quality('auto'));
return <AdvancedImage cldImg={image} />;
}
import { AdvancedImage, lazyload, placeholder } from '@cloudinary/react';
<AdvancedImage
cldImg={myImage}
plugins={[
lazyload(),
placeholder({ mode: 'blur' }) // blur, pixelate, vectorize
]}
/>
// next.config.js
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'res.cloudinary.com',
},
],
},
};
import Image from 'next/image';
function CloudinaryImage({ publicId, width, height }) {
const cloudName = process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME;
const src = `https://res.cloudinary.com/${cloudName}/image/upload/c_fill,w_${width},h_${height},q_auto,f_auto/${publicId}`;
return (
<Image
src={src}
alt=""
width={width}
height={height}
/>
);
}
npm install next-cloudinary
import { CldImage, CldUploadWidget } from 'next-cloudinary';
// Display image
<CldImage
src="products/shoe"
width="400"
height="300"
crop="fill"
gravity="auto"
alt="Product"
/>
// Upload widget
<CldUploadWidget
uploadPreset="my_preset"
onUpload={(result) => {
console.log(result.info.secure_url);
}}
>
{({ open }) => (
<button onClick={() => open()}>Upload</button>
)}
</CldUploadWidget>
// Video URL
const videoUrl = cloudinary.url('videos/sample', {
resource_type: 'video',
width: 640,
height: 360,
crop: 'fill',
quality: 'auto',
format: 'mp4',
});
// Thumbnail from video
const thumbnail = cloudinary.url('videos/sample', {
resource_type: 'video',
format: 'jpg',
start_offset: '5', // 5 seconds in
width: 400,
crop: 'fill',
});
// Animated GIF from video
const gif = cloudinary.url('videos/sample', {
resource_type: 'video',
format: 'gif',
start_offset: '2',
end_offset: '5',
width: 300,
});
// List resources
const resources = await cloudinary.api.resources({
type: 'upload',
prefix: 'products/',
max_results: 100,
});
// Get resource details
const resource = await cloudinary.api.resource('products/shoe');
// Delete resource
await cloudinary.uploader.destroy('products/old-shoe');
// Rename resource
await cloudinary.uploader.rename('old-name', 'new-name');
// Create folder
await cloudinary.api.create_folder('new-folder');
Configure in Cloudinary dashboard for unsigned uploads.
// Unsigned upload (client-side)
const formData = new FormData();
formData.append('file', file);
formData.append('upload_preset', 'my_preset');
const response = await fetch(
`https://api.cloudinary.com/v1_1/${cloudName}/image/upload`,
{ method: 'POST', body: formData }
);
const data = await response.json();
console.log(data.secure_url);
// Server: Generate signature
const timestamp = Math.round(new Date().getTime() / 1000);
const signature = cloudinary.utils.api_sign_request(
{ timestamp, folder: 'uploads' },
apiSecret
);
// Client: Upload with signature
const formData = new FormData();
formData.append('file', file);
formData.append('api_key', apiKey);
formData.append('timestamp', timestamp);
formData.append('signature', signature);
formData.append('folder', 'uploads');
await fetch(
`https://api.cloudinary.com/v1_1/${cloudName}/image/upload`,
{ method: 'POST', body: formData }
);
f_auto,q_auto for best optimizationThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.