cloudflare-images について
cloudflare-imagesは、画像の保存、配信、変換を行う開発者向けのCloudflare Imagesガイドです。Images API、変換、バリアントに加え、公開画像と非公開画像の扱いを説明します。
主な機能
- 01ファイルのアップロードと外部画像の取り込み
- 02ユーザー向け直接アップロードURLの発行
- 03画像のサイズ、形式、効果の変換
- 04名前付き・柔軟なバリアントの管理
- 05署名付きURLによる非公開画像の配信
活用シーン
- 01他サービスの画像をCloudflare Imagesへ移行
- 02APIキーを公開せずユーザーに画像をアップロードしてもらう
- 03端末サイズに応じたレスポンシブ画像の配信
- 04有効期限付きリンクで非公開画像を共有
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill cloudflare-imagesインストール後、Claude Code で/cloudflare-imagesを入力して読み込まれたか確認します。
同梱ファイルREADME.mdSKILL.json
詳細
Cloudflare Images
ステータス:本番環境で利用可能 ✅ 最終更新日:2025-10-26 依存関係:Images が有効になっている Cloudflare アカウント 最新バージョン:Cloudflare Images API v2
概要
Cloudflare Images には、次の 2 つの強力な機能があります。
- Images API:画像をアップロード、保存し、自動最適化とバリアントを利用して配信します
- 画像変換:公開アクセス可能な画像を任意にリサイズ、最適化、変換します
主なメリット:
- グローバル CDN による配信
- WebP/AVIF への自動変換
- 用途別のバリアント(最大 100 個)
- アップロードの直接作成(ユーザーは API キーなしでアップロードできます)
- 非公開画像用の署名付き URL
- URL または Workers を介した任意の画像の変換
クイックスタート(5 分)
1. Cloudflare Images を有効にする
Cloudflare ダッシュボードにログイン → Images → アカウントで有効にします。
アカウント ID を取得し、Cloudflare Images: Edit 権限を持つ API トークンを作成します。
これが重要な理由:
- すべての API 操作にアカウント ID と API トークンが必要です
- Images の Free プランには、変換回数の上限があります
2. 最初の画像をアップロードする
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'
レスポンスには次の情報が含まれます:
id:画像の配信用 IDvariants:配信用 URL の配列
重要:
multipart/form-dataエンコーディングを使用してください(application/jsonは使用しないでください)- 画像 ID は自動生成されます(またはカスタム ID を使用できます)
3. 画像を配信する
<img src="https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/public" />
デフォルトの public バリアントで画像を配信できます。独自のバリアント名に置き換えてください。
4. 画像変換を有効にする
ダッシュボード → Images → Transformations → 対象のゾーンを選択 → Enable for zone
これで、任意の画像を変換できます。
<img src="/cdn-cgi/image/width=800,quality=85/uploads/photo.jpg" />
これが重要な理由:
- Cloudflare Images の外部に保存された画像にも対応します
- Cloudflare のグローバルネットワーク上で自動的にキャッシュされます
- 追加のストレージ費用はかかりません
5. Workers で変換する(上級者向け)
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
}
}
});
}
};
3 つの機能
機能 1:Images API(アップロードとストレージ)
Cloudflare のネットワークに画像を保存し、世界中に配信します。
アップロード方法:
- ファイルのアップロード - サーバーからファイルを直接アップロードします
- URL によるアップロード - 外部 URL から画像を取り込みます
- アップロードの直接作成 - ユーザーのアップロード用に一度限りのアップロード URL を生成します
配信方法:
- デフォルトのドメイン:
imagedelivery.net - カスタムドメイン:
/cdn-cgi/imagedelivery/... - 署名付き URL:有効期限トークン付きの非公開画像
参照:templates/upload-api-basic.ts、templates/direct-creator-upload-backend.ts
機能 2:画像変換
画像(Images に保存されたもの、外部のものを問わず)を最適化し、リサイズします。
2 つの方法:
- URL による変換 - 特別な URL 形式を使用します
- Workers による変換 - fetch を介してプログラムから制御します
一般的な変換:
- リサイズ:
width=800,height=600,fit=cover - 最適化:
quality=85,format=auto - 効果:
blur=10,sharpen=3 - 切り抜き:
gravity=face,zoom=0.5
参照:templates/transform-via-url.ts、templates/transform-via-workers.ts
機能 3:バリアント
用途に応じて使い分けられる、あらかじめ定義された画像サイズです。
名前付きバリアント(最大 100 個):
- 一度作成すれば、どこでも使用できます
- 例:
thumbnail、avatar、hero - 変換内容を統一できます
フレキシブルバリアント(動的):
- アカウントごとに有効化します
- URL 内で変換パラメーターを使用します
- 例:
w=400,sharpen=3 - 署名付き URL とは併用できません
参照:templates/variants-management.ts、references/variants-guide.md
Images API - アップロード方法
方法 1:ファイルのアップロード(基本)
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"}'
主なオプション:
file:画像ファイル(必須)id:カスタム ID(任意、デフォルトでは自動生成)requireSignedURLs:非公開画像の場合はtrue(デフォルト:false)metadata:JSON オブジェクト(最大 1024 バイト、エンドユーザーには表示されません)
レスポンス:
{
"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"
]
}
}
参照:templates/upload-api-basic.ts
方法 2:URL 経由でアップロード
事前にダウンロードせず、外部ソースから画像を取り込みます。
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"}'
使用する場面:
- 別のサービスから画像を移行する場合
- ユーザーから提供された URL を取り込む場合
- 外部ソースの画像をバックアップする場合
重要:
- URL は公開アクセス可能であるか、認証が必要です
- HTTP ベーシック認証に対応しています:
https://user:[email protected]/image.jpg - 同じリクエストで
fileとurlを併用できません
参照:templates/upload-via-url.ts
方法 3:直接クリエーターアップロード ⭐
ユーザーが Cloudflare に直接アップロードするための使い捨てアップロード URL を生成します(API キーは公開されません)。
バックエンドのエンドポイント(アップロード URL を生成):
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
フロントエンドのアップロード(HTML + JavaScript):
<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>
重要な理由:
- ブラウザーに API キーを公開しません
- ユーザーは Cloudflare に直接アップロードします(より高速で、中継サーバーも不要です)
- 使い捨て URL は、使用後またはタイムアウト後に期限切れになります
- アップロードの成功/失敗を通知する Webhook を利用できます
重要な CORS の修正方法:
- ✅ 必須:
multipart/form-dataエンコーディングを使用します(ヘッダーはブラウザーに設定させます) - ✅ 必須:フィールド名には
fileを指定します(imageなど、ほかの名前は使用しないでください) - ✅ 必須:バックエンドからのみ
/direct_uploadAPI を呼び出します - ❌ 禁止:
Content-Type: application/jsonまたはimage/jpegを設定すること - ❌ 禁止:ブラウザーから
/direct_uploadを呼び出すこと(CORS エラーが発生します)
参照:templates/direct-creator-upload-backend.ts、templates/direct-creator-upload-frontend.html、references/direct-upload-complete-workflow.md
画像変換
URL 変換
特別な URL 形式を使って画像を変換します。
URL パターン:
https://<ZONE>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>
例:
<img src="/cdn-cgi/image/width=800,quality=85,format=auto/uploads/photo.jpg" />
よく使うオプション:
- サイズ:
width=800、height=600、fit=cover - 品質:
quality=85(1~100) - 形式:
format=auto(WebP/AVIF を自動検出)、format=webp、format=jpeg - トリミング:
gravity=auto(スマートトリミング)、gravity=face、trim=10 - 効果:
blur=10、sharpen=3、brightness=1.2、contrast=1.1 - 回転:
rotate=90、flip=h(水平反転)、flip=v(垂直反転)
フィットオプション:
scale-down:サイズに収まるよう縮小します(拡大はしません)contain:縦横比を維持して、指定サイズ内に収まるよう変更しますcover:指定サイズを満たすよう変更します(トリミングされる場合があります)crop:指定サイズに合わせてトリミングしますpad:サイズを変更して余白を追加します(backgroundオプションと併用します)
形式の自動検出:
<img src="/cdn-cgi/image/format=auto/image.jpg" />
Cloudflare は次の形式で配信します:
- AVIF 対応ブラウザー(Chrome、Edge)には AVIF
- AVIF 非対応ブラウザー(Safari、Firefox)には WebP
- フォールバックとして元の形式(JPEG)
参照:templates/transform-via-url.ts、references/transformation-options.md
Workers による変換
独自の URL スキームを使ったプログラムによる画像変換です。
基本パターン:
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
// Custom URL scheme: /images/thumbnail/photo.jpg
if (url.pathname.startsWith('/images/thumbnail/')) {
const imagePath = url.pathname.replace('/images/thumbnail/', '');
const imageURL = `https://storage.example.com/${imagePath}`;
return fetch(imageURL, {
cf: {
image: {
width: 300,
height: 300,
fit: 'cover',
quality: 85
}
}
});
}
return new Response('Not found', { status: 404 });
}
};
応用:コンテンツネゴシエーション:
const accept = request.headers.get('accept') || '';
let format: 'avif' | 'webp' | 'auto' = 'auto';
if (/image\/avif/.test(accept)) {
format = 'avif';
} else if (/image\/webp/.test(accept)) {
format = 'webp';
}
return fetch(imageURL, {
cf: {
image: {
format,
width: 800,
quality: 85
}
}
});
Workers による変換の利点:
- 独自の URL スキーム:画像の保存場所を隠せます
- プリセット名:ピクセル値の代わりに
thumbnail、avatar、largeを使えます - コンテンツネゴシエーション:ブラウザーに応じて最適な形式を配信できます
- アクセス制御:配信前に認証を確認できます
- 動的なサイズ設定:デバイスタイプに基づいてサイズを計算できます
参照:templates/transform-via-workers.ts、references/transformation-options.md
バリアント管理
名前付きバリアント(最大 100 個)
用途ごとに、事前定義した変換を作成します。
API 経由で作成:
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/variants" \
--header "Authorization: Bearer <API_TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"id": "avatar",
"options": {
"fit": "cover",
"width": 200,
"height": 200,
"metadata": "none"
},
"neverRequireSignedURLs": false
}'
URL で使用:
<img src="https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/avatar" />
使用する場面:
- アプリ全体で画像サイズを統一する場合
- プライベート画像(署名付き URL で使用できます)
- シンプルで予測しやすい URL が必要な場合
参照:templates/variants-management.ts
柔軟なバリアント
URL 内のパラメーターを使用して、動的に変換します。
有効化(アカウントごとに初回のみ):
curl --request PATCH \
https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/config \
--header "Authorization: Bearer <API_TOKEN>" \
--header "Content-Type: application/json" \
--data '{"flexible_variants": true}'
URL で使用:
<img src="https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/w=400,sharpen=3" />
使用する場面:
- サイズを動的に設定する必要がある場合
- パブリック画像のみ(署名付き URL では使用できません)
- 迅速なプロトタイピング
重要:
- ❌
requireSignedURLs=trueとは併用できません - ✅ プライベート画像には名前付きバリアントを使用してください
参照:references/variants-guide.md
署名付き URL(プライベート画像)
HMAC-SHA256 トークンを使用して、プライベート画像用の有効期限付き URL を生成します。
URL 形式:
https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/<VARIANT>?exp=<EXPIRY>&sig=<SIGNATURE>
署名の生成(Workers の例):
async function generateSignedURL(
imageId: string,
variant: string,
expirySeconds: number = 3600
): Promise<string> {
const accountHash = 'YOUR_ACCOUNT_HASH';
const signingKey = 'YOUR_SIGNING_KEY'; // Dashboard → Images → Keys
const expiry = Math.floor(Date.now() / 1000) + expirySeconds;
const stringToSign = `${imageId}${variant}${expiry}`;
const encoder = new TextEncoder();
const keyData = encoder.encode(signingKey);
const messageData = encoder.encode(stringToSign);
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
const sig = Array.from(new Uint8Array(signature))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return `https://imagedelivery.net/${accountHash}/${imageId}/${variant}?exp=${expiry}&sig=${sig}`;
}
使用方法:
const signedURL = await generateSignedURL('image-id', 'public', 3600);
// Returns URL valid for 1 hour
使用する場面:
- ユーザープロフィール写真(共有されるまでは非公開)
- 有料コンテンツ(有効期限付きアクセス)
- 一時的なダウンロード
- 安全な画像配信
参照先:templates/signed-urls-generation.ts、references/signed-urls-guide.md
レスポンシブ画像
画面サイズに応じて最適なサイズの画像を配信します。
名前付きバリアントを使用する場合:
<img
srcset="
https://imagedelivery.net/<HASH>/<ID>/mobile 480w,
https://imagedelivery.net/<HASH>/<ID>/tablet 768w,
https://imagedelivery.net/<HASH>/<ID>/desktop 1920w
"
sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1920px"
src="https://imagedelivery.net/<HASH>/<ID>/desktop"
alt="Responsive image"
/>
柔軟なバリアントを使用する場合:
<img
srcset="
https://imagedelivery.net/<HASH>/<ID>/w=480,f=auto 480w,
https://imagedelivery.net/<HASH>/<ID>/w=768,f=auto 768w,
https://imagedelivery.net/<HASH>/<ID>/w=1920,f=auto 1920w
"
sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1920px"
src="https://imagedelivery.net/<HASH>/<ID>/w=1920,f=auto"
alt="Responsive image"
/>
アートディレクション(モバイルとデスクトップで異なるトリミングを使用):
<picture>
<source
media="(max-width: 767px)"
srcset="https://imagedelivery.net/<HASH>/<ID>/mobile-square"
/>
<source
media="(min-width: 768px)"
srcset="https://imagedelivery.net/<HASH>/<ID>/desktop-wide"
/>
<img src="https://imagedelivery.net/<HASH>/<ID>/desktop-wide" alt="Hero image" />
</picture>
参照先:templates/responsive-images-srcset.html、references/responsive-images-patterns.md
重要なルール
必ず行うこと
✅ Direct Creator Upload には multipart/form-data を使用します
✅ ファイルフィールドには file という名前を付けます(image などの名前は使用しません)
✅ /direct_upload API はバックエンドからのみ呼び出します(ブラウザーからは呼び出しません)
✅ 変換には HTTPS URL を使用します(HTTP はサポートされていません)
✅ 画像パス内の特殊文字は URL エンコードします
✅ /cdn-cgi/image/ を使用する前に、ゾーンで変換を有効にします
✅ プライベート画像には名前付きバリアント(署名付き URL)を使用します
✅ 変換エラーを確認するには Cf-Resized ヘッダーを確認します
✅ WebP/AVIF への自動変換には format=auto を設定します
✅ 意図しない拡大を防ぐには fit=scale-down を使用します
絶対に行わないこと
❌ ファイルのアップロードに application/json の Content-Type を使用しません
❌ ブラウザーから /direct_upload を呼び出しません(CORS エラーが発生します)
❌ requireSignedURLs=true で柔軟なバリアントを使用しません
❌ SVG ファイルのサイズを変更しません(元から拡大縮小可能です)
❌ 変換に HTTP URL を使用しません(HTTPS のみ)
❌ URL にスペースやエスケープされていない Unicode を含めません
❌ Workers 内で同じ画像を複数回変換しません(9403 ループが発生します)
❌ 画像サイズを 100 メガピクセル以上にしません
❌ Workers で /cdn-cgi/image/ エンドポイントを使用しません(代わりに cf.image を使用します)
❌ 使用前にゾーンで変換を有効にするのを忘れません
既知の問題の予防
このスキルは、文書化されている 13 件以上の問題を防止します。
問題 #1:Direct Creator Upload の CORS エラー
エラー:Access to XMLHttpRequest blocked by CORS policy: Request header field content-type is not allowed
出典:Cloudflare Community #345739、#368114
原因:サーバーの CORS 設定では、Content-Type ヘッダーに multipart/form-data のみが許可されています
予防策:
// ✅ CORRECT
const formData = new FormData();
formData.append('file', fileInput.files[0]);
await fetch(uploadURL, {
method: 'POST',
body: formData // Browser sets multipart/form-data automatically
});
// ❌ WRONG
await fetch(uploadURL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }, // CORS error
body: JSON.stringify({ file: base64Image })
});
問題 #2:エラー 5408 - アップロードのタイムアウト
エラー:アップロード開始から約 15 秒後に Error 5408
出典:Cloudflare Community #571336
原因:Cloudflare のリクエストタイムアウトは 30 秒です。アップロードが遅い場合やファイルが大きい場合は、上限を超えます
予防策:
- アップロード前に画像を圧縮します(Canvas API を使用したクライアント側での圧縮)
- 適切なファイルサイズの上限を設定します(例:最大 10MB)
- ユーザーにアップロードの進行状況を表示します
- タイムアウトエラーを適切に処理します
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
if (file.size > MAX_FILE_SIZE) {
alert('File too large. Please select an image under 10MB.');
return;
}
問題 #3:エラー 400 - 無効なファイルパラメーター
エラー:400 Bad Request と、役に立たないエラーメッセージ
出典:Cloudflare Community #487629
原因:ファイルフィールドの名前は file である必要があります(image、photo などではありません)
予防策:
// ✅ CORRECT
formData.append('file', imageFile);
// ❌ WRONG
formData.append('image', imageFile); // 400 error
formData.append('photo', imageFile); // 400 error
問題 #4:CORS プリフライトの失敗
エラー:プリフライト OPTIONS リクエストがブロックされます
出典:Cloudflare Community #306805
原因:ブラウザーから /direct_upload API を直接呼び出しています(バックエンドからのみ呼び出す必要があります)
予防策:
ARCHITECTURE:
Browser → Backend API → POST /direct_upload → Returns uploadURL → Browser uploads to uploadURL
API トークンをブラウザーに公開しないでください。バックエンドでアップロード URL を生成し、フロントエンドに返します。
Issue #5:エラー 9401 - 引数が無効です
エラー:Cf-Resized: err=9401 - 必須の cf.image オプションがないか、無効です
出典:Cloudflare Images Docs - トラブルシューティング
発生する理由:必須の変換パラメーターがないか、値が無効です
防止策:
// ✅ CORRECT
fetch(imageURL, {
cf: {
image: {
width: 800,
quality: 85,
format: 'auto'
}
}
});
// ❌ WRONG
fetch(imageURL, {
cf: {
image: {
width: 'large', // Must be number
quality: 150 // Max 100
}
}
});
Issue #6:エラー 9402 - 画像が大きすぎます
エラー:Cf-Resized: err=9402 - 画像が大きすぎるか、接続が中断されました
出典:Cloudflare Images Docs - トラブルシューティング
発生する理由:画像が最大面積(100 メガピクセル)を超えているか、ダウンロードに失敗しました
防止策:
- 変換前に画像の寸法を検証します
- 適切なサイズのソース画像を使用します(最大 10000x10000px)
- ネットワークエラーを適切に処理します
Issue #7:エラー 9403 - リクエストループ
エラー:Cf-Resized: err=9403 - Worker が自身の URL またはすでにサイズ変更済みの画像を取得しています
出典:Cloudflare Images Docs - トラブルシューティング
発生する理由:変換済みの画像に変換を適用しているか、Worker が自身を取得しています
防止策:
// ✅ CORRECT
if (url.pathname.startsWith('/images/')) {
const originalPath = url.pathname.replace('/images/', '');
const originURL = `https://storage.example.com/${originalPath}`;
return fetch(originURL, { cf: { image: { width: 800 } } });
}
// ❌ WRONG
if (url.pathname.startsWith('/images/')) {
// Fetches worker's own URL, causes loop
return fetch(request, { cf: { image: { width: 800 } } });
}
Issue #8:エラー 9406/9419 - URL 形式が無効です
エラー:Cf-Resized: err=9406 または err=9419 - URL が HTTPS ではないか、URL にスペースまたはエスケープされていない Unicode が含まれています
出典:Cloudflare Images Docs - トラブルシューティング
発生する理由:画像 URL が HTTP(HTTPS ではない)を使用しているか、無効な文字が含まれています
防止策:
// ✅ CORRECT
const imageURL = "https://example.com/images/photo%20name.jpg";
// ❌ WRONG
const imageURL = "http://example.com/images/photo.jpg"; // HTTP not allowed
const imageURL = "https://example.com/images/photo name.jpg"; // Space not encoded
URL パスには必ず encodeURIComponent() を使用してください:
const filename = "photo name.jpg";
const imageURL = `https://example.com/images/${encodeURIComponent(filename)}`;
Issue #9:エラー 9412 - 画像以外のレスポンス
エラー:Cf-Resized: err=9412 - オリジンが画像ではなく HTML を返しました
出典:Cloudflare Images Docs - トラブルシューティング
発生する理由:オリジンサーバーが画像ではなく、404 ページまたはエラーページ(HTML)を返しています
防止策:
// Verify URL before transforming
const originResponse = await fetch(imageURL, { method: 'HEAD' });
const contentType = originResponse.headers.get('content-type');
if (!contentType?.startsWith('image/')) {
return new Response('Not an image', { status: 400 });
}
return fetch(imageURL, { cf: { image: { width: 800 } } });
Issue #10:エラー 9413 - 画像の最大面積を超えています
エラー:Cf-Resized: err=9413 - 画像が 100 メガピクセルを超えています
出典:Cloudflare Images Docs - トラブルシューティング
発生する理由:ソース画像の寸法が 100 メガピクセルを超えています(例:10000x10000px)
防止策:
- アップロード前に画像の寸法を検証します
- 大きすぎる画像を事前に処理します
- しきい値を超える画像を拒否します
const MAX_MEGAPIXELS = 100;
if (width * height > MAX_MEGAPIXELS * 1_000_000) {
return new Response('Image too large', { status: 413 });
}
Issue #11:フレキシブルバリアントと署名付き URL の非互換性
エラー:フレキシブルバリアントは非公開画像では機能しません
出典:Cloudflare Images Docs - フレキシブルバリアントを有効にする
発生する理由:フレキシブルバリアントは requireSignedURLs=true と併用できません
防止策:
// ✅ CORRECT - Use named variants for private images
await uploadImage({
file: imageFile,
requireSignedURLs: true // Use named variants: /public, /avatar, etc.
});
// ❌ WRONG - Flexible variants don't support signed URLs
// Cannot use: /w=400,sharpen=3 with requireSignedURLs=true
Issue #12:SVG のサイズ変更に関する制限
エラー:SVG ファイルは変換でサイズ変更できません
出典:Cloudflare Images Docs - SVG ファイル
発生する理由:SVG は本質的に拡大縮小可能なベクター形式であり、サイズ変更は適用できません
防止策:
// SVGs can be served but not resized
// Use any variant name as placeholder
// https://imagedelivery.net/<HASH>/<SVG_ID>/public
// SVG will be served at original size regardless of variant settings
Issue #13:EXIF メタデータはデフォルトで削除されます
エラー:アップロードした JPEG から GPS データやカメラ設定が削除されます
出典:Cloudflare Images Docs - URL による変換
発生する理由:デフォルトの動作では、著作権情報を除くすべてのメタデータが削除されます
防止策:
// Preserve metadata
fetch(imageURL, {
cf: {
image: {
width: 800,
metadata: 'keep' // Options: 'none', 'copyright', 'keep'
}
}
});
オプション:
none:すべてのメタデータを削除しますcopyright:著作権タグのみを保持します(JPEG のデフォルト)keep:GPS を含むほとんどの EXIF メタデータを保持します
バンドルされたリソースの使用
テンプレート(templates/)
よく使うパターンの、コピーしてすぐ使えるコードです。
- wrangler-images-binding.jsonc - Wrangler の設定(バインディングは不要です)
- upload-api-basic.ts - Images API にファイルをアップロードします
- upload-via-url.ts - 外部 URL から画像を取り込みます
- direct-creator-upload-backend.ts - 使い捨てのアップロード URL を生成します
- direct-creator-upload-frontend.html - ユーザー用のアップロードフォームです
- transform-via-url.ts - URL を使った変換の例です
- transform-via-workers.ts - Workers を使った変換パターンです
- variants-management.ts - バリアントを作成、一覧表示、削除します
- signed-urls-generation.ts - HMAC-SHA256 署名付き URL を生成します
- responsive-images-srcset.html - レスポンシブ画像のパターンです
- batch-upload.ts - 大量アップロード向けの Batch API です
使用方法:
cp templates/upload-api-basic.ts src/upload.ts
# Edit with your account ID and API token
リファレンス(references/)
Claude が必要に応じて読み込める、詳細なドキュメントです。
- api-reference.md - API エンドポイントの完全な一覧(アップロード、一覧表示、削除、バリアント)
- transformation-options.md - すべての変換パラメーターと例
- variants-guide.md - 名前付きバリアントとフレキシブルバリアント、およびそれぞれの使用方法
- signed-urls-guide.md - HMAC-SHA256 の実装の詳細
- direct-upload-complete-workflow.md - アーキテクチャとフローの全体像
- responsive-images-patterns.md - srcset、sizes、アートディレクション
- format-optimization.md - WebP/AVIF への自動変換戦略
- top-errors.md - 13 件以上のエラーと詳細なトラブルシューティング
読み込むタイミング:
- 特定の機能を詳しく調べるとき
- 複雑な問題をトラブルシューティングするとき
- API の詳細を理解するとき
- 高度なパターンを実装するとき
スクリプト(scripts/)
check-versions.sh - API エンドポイントが最新かどうかを確認します
高度なトピック
カスタムドメイン
imagedelivery.net の代わりに、独自のドメインから画像を配信します。
URL 形式:
https://example.com/cdn-cgi/imagedelivery/<ACCOUNT_HASH>/<IMAGE_ID>/<VARIANT>
要件:
- ドメインが Cloudflare 上にあること(Images と同じアカウント)
- Cloudflare 経由でプロキシされていること(オレンジ色の雲)
カスタムパス(Transform Rules):
/images/... を /cdn-cgi/imagedelivery/... に書き換えます:
- ダッシュボード → Rules → Transform Rules → Rewrite URL
- 一致条件:
starts_with(http.request.uri.path, "/images/") - 書き換え先:
/cdn-cgi/imagedelivery/<ACCOUNT_HASH>${substring(http.request.uri.path, 7)}
これで /images/{id}/{variant} は /cdn-cgi/imagedelivery/{hash}/{id}/{variant} に変わります。
Batch API
バッチトークンを使った大量アップロードです。
ホスト:api.cloudflare.com の代わりに batch.imagedelivery.net
使用方法:
# Create batch token in dashboard: Images → Batch API
curl "https://batch.imagedelivery.net/images/v1" \
--header "Authorization: Bearer <BATCH_TOKEN>" \
--form 'file=@./image.jpg'
使用する場面:
- 数千枚の画像を移行するとき
- 一括アップロードのワークフロー
- 画像の取り込みを自動化するとき
参照:templates/batch-upload.ts
Webhook
アップロードの成功または失敗に関する通知を受け取ります(Direct Creator Upload のみ)。
設定方法:
- ダッシュボード → Notifications → Destinations → Webhooks → Create
- Webhook URL を入力してテストします
- Notifications → All Notifications → Add → Images → Select webhook
ペイロード(例):
{
"imageId": "2cdc28f0-017a-49c4-9ed7-87056c83901",
"status": "uploaded",
"metadata": {"userId": "12345"}
}
使用する場面:
- アップロード後にデータベースを更新するとき
- 画像処理パイプラインを起動するとき
- アップロード状況をユーザーに通知するとき
トラブルシューティング
問題:画像が変換されない
症状:/cdn-cgi/image/... が元の画像を返す、または 404 を返します
解決方法:
- ゾーンで変換を有効にします:ダッシュボード → Images → Transformations → Enable for zone
- ゾーンが Cloudflare 経由でプロキシされていることを確認します(オレンジ色の雲)
- 元画像が公開アクセス可能であることを確認します
- 設定が反映されるまで 5~10 分待ちます
問題:Direct Upload で CORS エラーが発生する
症状:ブラウザーのコンソールに Access-Control-Allow-Origin エラーが表示されます
解決方法:
multipart/form-data形式を使用します(Content-Type はブラウザーに設定させてください)- ブラウザーから
/direct_uploadを呼び出さず、バックエンドから呼び出します - ファイルフィールドの名前を
fileにします(imageではありません) - 手動で設定した Content-Type ヘッダーを削除します
問題:Worker の変換で 9403 ループエラーが発生する
症状:レスポンスヘッダーに Cf-Resized: err=9403 が含まれる
解決策:
- Worker 自身の URL を取得しないようにします(外部オリジンを使用します)
- すでにサイズ変更された画像を変換しないようにします
- ループを避けるため、URL のルーティングロジックを確認します
問題:署名付き URL が機能しない
症状:署名付き URL にアクセスすると 403 Forbidden が返される
解決策:
- 画像が
requireSignedURLs=trueでアップロードされたことを確認します - 署名の生成方法(HMAC-SHA256)を確認します
- 有効期限のタイムスタンプが未来になっていることを確認します
- 署名キーがダッシュボード(Images → Keys)と一致することを確認します
- 署名付き URL ではフレキシブルバリアントを使用できません(名前付きバリアントを使用します)
問題:画像はアップロードされたが表示されない
症状:アップロードは 200 OK を返すが、画像がダッシュボードに表示されない
解決策:
- レスポンスに
draft: trueが含まれていないか確認します(Direct Creator Upload) - アップロードが完了するまで待ちます(GET
/images/v1/{id}で確認します) - アカウント ID が一致することを確認します
- Webhook でアップロードエラーを確認します
セットアップの完全なチェックリスト
- Images が有効になっている Cloudflare アカウント
- アカウント ID と API トークンを取得済み(Images: Edit 権限)
- (任意)ゾーンで画像変換が有効
- (任意)一般的なユースケース向けのバリアントを作成済み
- (任意)動的なサイズ指定が必要な場合は、フレキシブルバリアントを有効化済み
- (任意)プライベート画像用の署名キーを取得済み
- (任意)アップロード通知用に Webhook を設定済み
- (任意)Transform Rules でカスタムドメインを設定済み
- アップロード方法を実装済み(ファイル、URL、または Direct Creator)
- 配信 URL をテスト済み(imagedelivery.net またはカスタムドメイン)
- 変換をテスト済み(URL または Workers)
- エラー処理を実装済み(CORS、タイムアウト、サイズ制限)
公式ドキュメント
- Cloudflare Images: https://developers.cloudflare.com/images/
- はじめに: https://developers.cloudflare.com/images/get-started/
- 画像のアップロード: https://developers.cloudflare.com/images/upload-images/
- Direct Creator Upload: https://developers.cloudflare.com/images/upload-images/direct-creator-upload/
- 画像の変換: https://developers.cloudflare.com/images/transform-images/
- URL 経由の変換: https://developers.cloudflare.com/images/transform-images/transform-via-url/
- Workers 経由の変換: https://developers.cloudflare.com/images/transform-images/transform-via-workers/
- バリアントの作成: https://developers.cloudflare.com/images/manage-images/create-variants/
- プライベート画像の配信: https://developers.cloudflare.com/images/manage-images/serve-images/serve-private-images/
- トラブルシューティング: https://developers.cloudflare.com/images/reference/troubleshooting/
- API リファレンス: https://developers.cloudflare.com/api/resources/images/
パッケージのバージョン(2025-10-26 確認済み)
API バージョン:v2(直接アップロード用)、v1(標準アップロード用)
npm パッケージは不要 - Cloudflare のネイティブ API を使用します
任意:
@cloudflare/workers-types@latest- Workers 用の TypeScript 型
質問や問題がありますか?
- よくある問題については
references/top-errors.mdを確認します - セットアップ手順をすべて確認します
- 公式ドキュメントを確認します:https://developers.cloudflare.com/images/
- ゾーンで変換が有効になっていることを確認します
- Direct Creator Upload の CORS 設定を確認します