Claude
Skills
Sign in
Back

cloudflare-images

Included with Lifetime
$97 forever

This skill provides comprehensive knowledge for Cloudflare Images, covering both the Images API (upload/storage) and Image Transformations (optimize any image). It should be used when uploading images to Cloudflare, resizing images, optimizing image delivery, implementing direct creator uploads, creating image variants, generating signed URLs for private images, transforming images via Workers, or encountering image upload/transformation errors. Use when: setting up Cloudflare Images storage, implementing user-uploaded images, creating responsive images, optimizing image formats (WebP/AVIF), resizing images via URL or Workers, debugging CORS errors with direct uploads, handling image transformation errors (9401-9413), implementing signed URLs, managing image variants, or building image CDNs. Keywords: cloudflare images, image upload cloudflare, imagedelivery.net, cloudflare image transformations, /cdn-cgi/image/, direct creator upload, image variants, cf.image workers, signed urls images, flexible variants, webp avif conversion, responsive images cloudflare, error 5408, error 9401, error 9403, CORS direct upload, multipart/form-data, image optimization cloudflare

Ads & Marketing

What this skill does


# Cloudflare Images

**Status**: Production Ready ✅
**Last Updated**: 2025-10-26
**Dependencies**: Cloudflare account with Images enabled
**Latest Versions**: Cloudflare Images API v2

---

## Overview

Cloudflare Images provides two powerful features:

1. **Images API**: Upload, store, and serve images with automatic optimization and variants
2. **Image Transformations**: Resize, optimize, and transform any publicly accessible image

**Key Benefits**:
- Global CDN delivery
- Automatic WebP/AVIF conversion
- Variants for different use cases (up to 100)
- Direct creator upload (user uploads without API keys)
- Signed URLs for private images
- Transform any image via URL or Workers

---

## Quick Start (5 Minutes)

### 1. Enable Cloudflare Images

Log into Cloudflare dashboard → **Images** → Enable for your account.

Get your Account ID and create an API token with **Cloudflare Images: Edit** permissions.

**Why this matters:**
- Account ID and API token are required for all API operations
- Images Free plan includes limited transformations

### 2. Upload Your First Image

```bash
curl --request POST \
  --url https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/images/v1 \
  --header 'Authorization: Bearer <API_TOKEN>' \
  --header 'Content-Type: multipart/form-data' \
  --form 'file=@./image.jpg'
```

Response includes:
- `id`: Image ID for serving
- `variants`: Array of delivery URLs

**CRITICAL:**
- Use `multipart/form-data` encoding (NOT `application/json`)
- Image ID is automatically generated (or use custom ID)

### 3. Serve the Image

```html
<img src="https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/public" />
```

Default `public` variant serves the image. Replace with your own variant names.

### 4. Enable Image Transformations

Dashboard → **Images** → **Transformations** → Select your zone → **Enable for zone**

Now you can transform ANY image:

```html
<img src="/cdn-cgi/image/width=800,quality=85/uploads/photo.jpg" />
```

**Why this matters:**
- Works on images stored OUTSIDE Cloudflare Images
- Automatic caching on Cloudflare's global network
- No additional storage costs

### 5. Transform via Workers (Advanced)

```typescript
export default {
  async fetch(request: Request): Promise<Response> {
    const imageURL = "https://example.com/image.jpg";

    return fetch(imageURL, {
      cf: {
        image: {
          width: 800,
          quality: 85,
          format: "auto" // WebP/AVIF for supporting browsers
        }
      }
    });
  }
};
```

---

## The 3-Feature System

### Feature 1: Images API (Upload & Storage)

Store images on Cloudflare's network and serve them globally.

**Upload Methods**:
1. **File Upload** - Upload files directly from your server
2. **Upload via URL** - Ingest images from external URLs
3. **Direct Creator Upload** - Generate one-time upload URLs for user uploads

**Serving Options**:
- Default domain: `imagedelivery.net`
- Custom domains: `/cdn-cgi/imagedelivery/...`
- Signed URLs: Private images with expiry tokens

**See**: `templates/upload-api-basic.ts`, `templates/direct-creator-upload-backend.ts`

### Feature 2: Image Transformations

Optimize and resize ANY image (stored in Images or external).

**Two Methods**:
1. **URL Transformations** - Special URL format
2. **Workers Transformations** - Programmatic control via fetch

**Common Transformations**:
- Resize: `width=800,height=600,fit=cover`
- Optimize: `quality=85,format=auto`
- Effects: `blur=10,sharpen=3`
- Crop: `gravity=face,zoom=0.5`

**See**: `templates/transform-via-url.ts`, `templates/transform-via-workers.ts`

### Feature 3: Variants

Predefined image sizes for different use cases.

**Named Variants** (up to 100):
- Create once, use everywhere
- Example: `thumbnail`, `avatar`, `hero`
- Consistent transformations

**Flexible Variants** (dynamic):
- Enable per account
- Use transformation params in URL
- Example: `w=400,sharpen=3`
- **Cannot use with signed URLs**

**See**: `templates/variants-management.ts`, `references/variants-guide.md`

---

## Images API - Upload Methods

### Method 1: File Upload (Basic)

```bash
curl --request POST \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1 \
  --header "Authorization: Bearer <API_TOKEN>" \
  --header "Content-Type: multipart/form-data" \
  --form 'file=@./image.jpg' \
  --form 'requireSignedURLs=false' \
  --form 'metadata={"key":"value"}'
```

**Key Options**:
- `file`: Image file (required)
- `id`: Custom ID (optional, default auto-generated)
- `requireSignedURLs`: `true` for private images (default: `false`)
- `metadata`: JSON object (max 1024 bytes, not visible to end users)

**Response**:
```json
{
  "result": {
    "id": "2cdc28f0-017a-49c4-9ed7-87056c83901",
    "filename": "image.jpg",
    "uploaded": "2022-01-31T16:39:28.458Z",
    "requireSignedURLs": false,
    "variants": [
      "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0.../public"
    ]
  }
}
```

**See**: `templates/upload-api-basic.ts`

### Method 2: Upload via URL

Ingest images from external sources without downloading first.

```bash
curl --request POST \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1 \
  --header "Authorization: Bearer <API_TOKEN>" \
  --form 'url=https://example.com/image.jpg' \
  --form 'metadata={"source":"external"}'
```

**When to use**:
- Migrating images from another service
- Ingesting user-provided URLs
- Backing up images from external sources

**CRITICAL:**
- URL must be publicly accessible or authenticated
- Supports HTTP basic auth: `https://user:[email protected]/image.jpg`
- Cannot use both `file` and `url` in same request

**See**: `templates/upload-via-url.ts`

### Method 3: Direct Creator Upload ⭐

Generate one-time upload URLs for users to upload directly to Cloudflare (no API key exposure).

**Backend Endpoint** (generate upload URL):
```typescript
const response = await fetch(
  `https://api.cloudflare.com/client/v4/accounts/${accountId}/images/v2/direct_upload`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      requireSignedURLs: true,
      metadata: { userId: '12345' },
      expiry: '2025-10-26T18:00:00Z' // Optional: default 30min, max 6hr
    })
  }
);

const { uploadURL, id } = await response.json();
// Return uploadURL to frontend
```

**Frontend Upload** (HTML + JavaScript):
```html
<form id="upload-form">
  <input type="file" id="file-input" accept="image/*" />
  <button type="submit">Upload</button>
</form>

<script>
document.getElementById('upload-form').addEventListener('submit', async (e) => {
  e.preventDefault();

  const fileInput = document.getElementById('file-input');
  const formData = new FormData();
  formData.append('file', fileInput.files[0]); // MUST be named 'file'

  const uploadURL = 'UPLOAD_URL_FROM_BACKEND'; // Get from backend

  const response = await fetch(uploadURL, {
    method: 'POST',
    body: formData // NO Content-Type header, browser sets multipart/form-data
  });

  if (response.ok) {
    console.log('Upload successful!');
  }
});
</script>
```

**Why this matters:**
- No API key exposure to browser
- Users upload directly to Cloudflare (faster, no intermediary server)
- One-time URL expires after use or timeout
- Webhooks available for upload success/failure notifications

**CRITICAL CORS FIX**:
- ✅ **DO**: Use `multipart/form-data` encoding (let browser set header)
- ✅ **DO**: Name field `file` (NOT `image` or other names)
- ✅ **DO**: Call `/direct_upload` API from backend only
- ❌ **DON'T**: Set `Content-Type: application/json` or `image/jpeg`
- ❌ **DON'T**: Call `/direct_upload` from browser (CORS will fail)

**See**: `templates/direct-creator-upload-backend.ts`, `templates/direct-creator-upload-frontend.html`, `references/direct-upload-complete-workflow.md`

---

## Image Transformations

### URL Transformations

Transform images using a special 

Related in Ads & Marketing