Files
2026-01-30 03:04:10 +00:00

4.0 KiB

Configuration

Wrangler Integration

Workers Binding Setup

Add to wrangler.toml:

name = "my-image-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[images]
binding = "IMAGES"

Access in Worker:

interface Env {
  IMAGES: ImageBinding;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    return await env.IMAGES
      .input(imageBuffer)
      .transform({ width: 800 })
      .output()
      .response();
  }
};

Upload via Script

Wrangler doesn't have built-in Images commands, use REST API:

// scripts/upload-image.ts
import fs from 'fs';
import FormData from 'form-data';

async function uploadImage(filePath: string) {
  const accountId = process.env.CLOUDFLARE_ACCOUNT_ID!;
  const apiToken = process.env.CLOUDFLARE_API_TOKEN!;
  
  const formData = new FormData();
  formData.append('file', fs.createReadStream(filePath));
  
  const response = await fetch(
    `https://api.cloudflare.com/client/v4/accounts/${accountId}/images/v1`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiToken}`,
      },
      body: formData,
    }
  );
  
  const result = await response.json();
  console.log('Uploaded:', result);
}

uploadImage('./photo.jpg');

Environment Variables

Store account hash for URL construction:

[vars]
IMAGES_ACCOUNT_HASH = "your-account-hash"
ACCOUNT_ID = "your-account-id"

Access in Worker:

const imageUrl = `https://imagedelivery.net/${env.IMAGES_ACCOUNT_HASH}/${imageId}/public`;

Variants Configuration

Variants are named presets for transformations.

Create Variant (Dashboard)

  1. Navigate to Images → Variants
  2. Click "Create Variant"
  3. Set name (e.g., thumbnail)
  4. Configure: width=200,height=200,fit=cover

Create Variant (API)

curl -X POST \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/variants \
  -H "Authorization: Bearer {api_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "thumbnail",
    "options": {
      "width": 200,
      "height": 200,
      "fit": "cover"
    },
    "neverRequireSignedURLs": true
  }'

Use Variant

https://imagedelivery.net/{account_hash}/{image_id}/thumbnail

Common Variant Presets

{
  "thumbnail": {
    "width": 200,
    "height": 200,
    "fit": "cover"
  },
  "avatar": {
    "width": 128,
    "height": 128,
    "fit": "cover",
    "gravity": "face"
  },
  "hero": {
    "width": 1920,
    "height": 1080,
    "fit": "cover",
    "quality": 90
  },
  "mobile": {
    "width": 640,
    "fit": "scale-down",
    "quality": 80,
    "format": "avif"
  }
}

Authentication

Generate at: Dashboard → My Profile → API Tokens

Required permissions:

  • Account → Cloudflare Images → Edit
curl -H "Authorization: Bearer {api_token}" \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1

API Key (Legacy)

curl -H "X-Auth-Email: {email}" \
     -H "X-Auth-Key: {api_key}" \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1

Signed URLs

For private images, enable signed URLs:

# Upload with signed URLs required
curl -X POST \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1 \
  -H "Authorization: Bearer {api_token}" \
  -F file=@private.jpg \
  -F requireSignedURLs=true

Generate signed URL:

import { createHmac } from 'crypto';

function signUrl(imageId: string, variant: string, expiry: number, key: string): string {
  const path = `/${imageId}/${variant}`;
  const toSign = `${path}${expiry}`;
  const signature = createHmac('sha256', key)
    .update(toSign)
    .digest('hex');
  
  return `https://imagedelivery.net/{hash}${path}?exp=${expiry}&sig=${signature}`;
}

// Sign URL valid for 1 hour
const signedUrl = signUrl('image-id', 'public', Date.now() + 3600, env.SIGNING_KEY);

Local Development

npx wrangler dev --remote

Must use --remote for Images binding access.