Cloudflare Images
End-to-end image storage, transformation, and delivery solution on Cloudflare's global network.
Quick Navigation
- Upload methods →
references/upload.md
- Transformations →
references/transformations.md
- Variants →
references/variants.md
- Workers binding →
references/binding.md
- Polish →
references/polish.md
- Signed URLs →
references/security.md
- Pricing →
references/pricing.md
When to Use
- Storing and delivering optimized images at scale
- Transforming remote images on-the-fly
- Resizing, cropping, converting image formats
- Adding watermarks to images
- Serving responsive images with
srcset
- Protecting images with signed URLs
- Optimizing images from R2 storage
Two Usage Modes
| Mode |
Description |
Billing |
| Storage in Images |
Upload images to Cloudflare, serve via variants |
Images Stored + Images Delivered |
| Transform remote |
Optimize images from any origin (R2, S3, etc.) |
Images Transformed (unique/30d) |
Quick Start
Upload an Image (API)
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
Transform via URL
<img src="/cdn-cgi/image/width=400,quality=80,format=auto/uploads/hero.jpg" />
Transform via Workers
fetch(imageURL, {
cf: {
image: {
width: 800,
height: 600,
fit: "cover",
format: "auto",
},
},
});
URL Format
https://<ZONE>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>
<ZONE> — your Cloudflare domain
/cdn-cgi/image/ — fixed prefix for image transformations
<OPTIONS> — comma-separated: width=400,quality=80,format=auto
<SOURCE-IMAGE> — absolute path or full URL
Stored Images Delivery
https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/<VARIANT_NAME>
Transformation Options
| Option |
Description |
Example |
width |
Max width in pixels |
width=800 |
height |
Max height in pixels |
height=600 |
fit |
Resize mode |
fit=cover |
format |
Output format |
format=auto |
quality |
JPEG/WebP/AVIF quality 1-100 |
quality=85 |
gravity |
Crop focus point |
gravity=face, gravity=auto |
blur |
Blur radius 1-250 |
blur=50 |
sharpen |
Sharpening 0-10 |
sharpen=1 |
rotate |
Rotation degrees |
rotate=90 |
trim |
Remove pixels from edges |
trim=20;30;20;0 |
Fit Modes
| Mode |
Behavior |
scale-down |
Shrink only, never enlarge |
contain |
Fit within dimensions, preserve aspect ratio |
cover |
Fill dimensions, crop if needed |
crop |
Like cover but never enlarges |
pad |
Fit within, add background color |
Format Auto
format=auto serves WebP or AVIF based on browser support. Use with Accept header parsing in Workers.
Supported Formats
Input
- JPEG, PNG, GIF (animated), WebP (animated), SVG, HEIC
Output
- JPEG, PNG, GIF, WebP, AVIF, SVG (passthrough)
Note: HEIC must be served as AVIF/WebP/JPEG/PNG. SVG is not resized (inherently scalable).
Limits
| Constraint |
Limit |
| Max image dimension |
12,000 pixels |
| Max image area |
100 megapixels |
| Max file size (transformations) |
70 MB |
| Max file size (storage) |
10 MB |
| GIF/WebP animation |
50 megapixels total |
| AVIF output hard limit |
1,200 px (1,600 explicit) |
| Variants per account |
100 |
Workers Integration
Images Binding Setup
# wrangler.toml
[images]
binding = "IMAGES"
Transform with Binding
const response = (await env.IMAGES.input(stream).transform({ width: 800 }).transform({ blur: 20 }).output({ format: "image/avif" })).response();
Draw Watermark
const watermark = await fetch("https://example.com/watermark.png");
const image = await fetch("https://example.com/photo.jpg");
const response = (
await env.IMAGES.input(image.body)
.draw(env.IMAGES.input(watermark.body).transform({ width: 100 }), { bottom: 10, right: 10, opacity: 0.75 })
.output({ format: "image/avif" })
).response();
Get Image Info
const info = await env.IMAGES.info(stream);
// { format, fileSize, width, height }
Recipes
Responsive Images with srcset
<img srcset="/cdn-cgi/image/width=320/photo.jpg 320w, /cdn-cgi/image/width=640/photo.jpg 640w, /cdn-cgi/image/width=1280/photo.jpg 1280w" sizes="(max-width: 640px) 100vw, 640px" src="/cdn-cgi/image/width=640/photo.jpg" alt="Responsive image" />
Face-Aware Cropping
fetch(imageURL, {
cf: {
image: {
width: 200,
height: 200,
fit: "cover",
gravity: "face",
zoom: 0.5, // 0 = more background, 1 = tight crop
},
},
});
Direct Creator Upload
# Get one-time upload URL
curl --request POST \
https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v2/direct_upload \
--header "Authorization: Bearer <API_TOKEN>"
# Response: { "uploadURL": "https://upload.imagedelivery.net/..." }
Upload from Worker
const image = await fetch("https://example.com/image.png");
const bytes = await image.bytes();
const formData = new FormData();
formData.append("file", new File([bytes], "image.png"));
await fetch(`https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/images/v1`, {
method: "POST",
headers: { Authorization: `Bearer ${TOKEN}` },
body: formData,
});
Critical Prohibitions
- NEVER set up Image Resizing Worker for entire zone (
/*) — blocks non-image requests
- NEVER activate Polish and image transformations simultaneously — redundant compression
- NEVER use flexible variants with signed URL tokens — incompatible
- NEVER use custom ID paths with
requireSignedURLs=true — not supported
- NEVER expect SVG resizing — SVGs are passed through as-is
- NEVER include resizing options in
cacheKey — fragments cache
Troubleshooting
No Cf-Resized Header
- Transformations not enabled on zone
- Another Worker intercepting request
- Using dashboard preview (doesn't simulate transforms)
Common Error Codes
| Code |
Meaning |
| 9401 |
Invalid transformation options |
| 9402 |
Image too large |
| 9403 |
Request loop detected |
| 9422 |
Free tier limit exceeded (5,000/month) |
| 9520 |
Unsupported format |
Related Skills
cloudflare-workers - For serverless compute
cloudflare-pages - For full-stack apps
cloudflare-r2 - R2 object storage
1---2name: cloudflare-images-33description: Store, transform, and deliver optimized images with Cloudflare Images. Covers image upload (API, Worker, Direct Creator Upload), variants, transformations (URL and Workers), bindings, Polish, signed URLs, formats (AVIF, WebP), R2 integration, watermarks. Keywords: Cloudflare Images, image transformations, variants, /cdn-cgi/image/, imagedelivery.net, Polish, AVIF, WebP, signed URLs, Direct Creator Upload, Images binding, R2, watermark.4---5
6# Cloudflare Images
7
8End-to-end image storage, transformation, and delivery solution on Cloudflare's global network.
9
10## Quick Navigation
11
12- Upload methods → `references/upload.md`
13- Transformations → `references/transformations.md`
14- Variants → `references/variants.md`
15- Workers binding → `references/binding.md`
16- Polish → `references/polish.md`
17- Signed URLs → `references/security.md`
18- Pricing → `references/pricing.md`
19
20## When to Use
21
22- Storing and delivering optimized images at scale
23- Transforming remote images on-the-fly
24- Resizing, cropping, converting image formats
25- Adding watermarks to images
26- Serving responsive images with `srcset`
27- Protecting images with signed URLs
28- Optimizing images from R2 storage
29
30## Two Usage Modes
31
32| Mode | Description | Billing |
33| ----------------- | ----------------------------------------------- | -------------------------------- |
34| Storage in Images | Upload images to Cloudflare, serve via variants | Images Stored + Images Delivered |
35| Transform remote | Optimize images from any origin (R2, S3, etc.) | Images Transformed (unique/30d) |
36
37## Quick Start
38
39### Upload an Image (API)
40
41```bash
42curl --request POST \
43 --url https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/images/v1 \
44 --header 'Authorization: Bearer <API_TOKEN>' \
45 --header 'Content-Type: multipart/form-data' \
46 --form file=@./image.jpg
47```
48
49### Transform via URL
50
51```html
52<img src="/cdn-cgi/image/width=400,quality=80,format=auto/uploads/hero.jpg" />
53```
54
55### Transform via Workers
56
57```js
58fetch(imageURL, {
59 cf: {
60 image: {
61 width: 800,
62 height: 600,
63 fit: "cover",
64 format: "auto",
65 },
66 },
67});
68```
69
70## URL Format
71
72```
73https://<ZONE>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>
74```
75
76- `<ZONE>` — your Cloudflare domain
77- `/cdn-cgi/image/` — fixed prefix for image transformations
78- `<OPTIONS>` — comma-separated: `width=400,quality=80,format=auto`
79- `<SOURCE-IMAGE>` — absolute path or full URL
80
81### Stored Images Delivery
82
83```
84https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/<VARIANT_NAME>
85```
86
87## Transformation Options
88
89| Option | Description | Example |
90| --------- | ---------------------------- | ------------------------------ |
91| `width` | Max width in pixels | `width=800` |
92| `height` | Max height in pixels | `height=600` |
93| `fit` | Resize mode | `fit=cover` |
94| `format` | Output format | `format=auto` |
95| `quality` | JPEG/WebP/AVIF quality 1-100 | `quality=85` |
96| `gravity` | Crop focus point | `gravity=face`, `gravity=auto` |
97| `blur` | Blur radius 1-250 | `blur=50` |
98| `sharpen` | Sharpening 0-10 | `sharpen=1` |
99| `rotate` | Rotation degrees | `rotate=90` |
100| `trim` | Remove pixels from edges | `trim=20;30;20;0` |
101
102### Fit Modes
103
104| Mode | Behavior |
105| ------------ | -------------------------------------------- |
106| `scale-down` | Shrink only, never enlarge |
107| `contain` | Fit within dimensions, preserve aspect ratio |
108| `cover` | Fill dimensions, crop if needed |
109| `crop` | Like cover but never enlarges |
110| `pad` | Fit within, add background color |
111
112### Format Auto
113
114`format=auto` serves WebP or AVIF based on browser support. Use with Accept header parsing in Workers.
115
116## Supported Formats
117
118### Input
119
120- JPEG, PNG, GIF (animated), WebP (animated), SVG, HEIC
121
122### Output
123
124- JPEG, PNG, GIF, WebP, AVIF, SVG (passthrough)
125
126**Note:** HEIC must be served as AVIF/WebP/JPEG/PNG. SVG is not resized (inherently scalable).
127
128## Limits
129
130| Constraint | Limit |
131| ------------------------------- | ------------------------- |
132| Max image dimension | 12,000 pixels |
133| Max image area | 100 megapixels |
134| Max file size (transformations) | 70 MB |
135| Max file size (storage) | 10 MB |
136| GIF/WebP animation | 50 megapixels total |
137| AVIF output hard limit | 1,200 px (1,600 explicit) |
138| Variants per account | 100 |
139
140## Workers Integration
141
142### Images Binding Setup
143
144```toml
145# wrangler.toml
146[images]
147binding = "IMAGES"
148```
149
150### Transform with Binding
151
152```ts
153const response = (await env.IMAGES.input(stream).transform({ width: 800 }).transform({ blur: 20 }).output({ format: "image/avif" })).response();
154```
155
156### Draw Watermark
157
158```ts
159const watermark = await fetch("https://example.com/watermark.png");
160const image = await fetch("https://example.com/photo.jpg");
161
162const response = (
163 await env.IMAGES.input(image.body)
164 .draw(env.IMAGES.input(watermark.body).transform({ width: 100 }), { bottom: 10, right: 10, opacity: 0.75 })
165 .output({ format: "image/avif" })
166).response();
167```
168
169### Get Image Info
170
171```ts
172const info = await env.IMAGES.info(stream);
173// { format, fileSize, width, height }
174```
175
176## Recipes
177
178### Responsive Images with srcset
179
180```html
181<img srcset="/cdn-cgi/image/width=320/photo.jpg 320w, /cdn-cgi/image/width=640/photo.jpg 640w, /cdn-cgi/image/width=1280/photo.jpg 1280w" sizes="(max-width: 640px) 100vw, 640px" src="/cdn-cgi/image/width=640/photo.jpg" alt="Responsive image" />
182```
183
184### Face-Aware Cropping
185
186```js
187fetch(imageURL, {
188 cf: {
189 image: {
190 width: 200,
191 height: 200,
192 fit: "cover",
193 gravity: "face",
194 zoom: 0.5, // 0 = more background, 1 = tight crop
195 },
196 },
197});
198```
199
200### Direct Creator Upload
201
202```bash
203# Get one-time upload URL
204curl --request POST \
205 https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v2/direct_upload \
206 --header "Authorization: Bearer <API_TOKEN>"
207
208# Response: { "uploadURL": "https://upload.imagedelivery.net/..." }
209```
210
211### Upload from Worker
212
213```ts
214const image = await fetch("https://example.com/image.png");
215const bytes = await image.bytes();
216
217const formData = new FormData();
218formData.append("file", new File([bytes], "image.png"));
219
220await fetch(`https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/images/v1`, {
221 method: "POST",
222 headers: { Authorization: `Bearer ${TOKEN}` },
223 body: formData,
224});
225```
226
227## Critical Prohibitions
228
2291. **NEVER** set up Image Resizing Worker for entire zone (`/*`) — blocks non-image requests
2302. **NEVER** activate Polish and image transformations simultaneously — redundant compression
2313. **NEVER** use flexible variants with signed URL tokens — incompatible
2324. **NEVER** use custom ID paths with `requireSignedURLs=true` — not supported
2335. **NEVER** expect SVG resizing — SVGs are passed through as-is
2346. **NEVER** include resizing options in `cacheKey` — fragments cache
235
236## Troubleshooting
237
238### No `Cf-Resized` Header
239
240- Transformations not enabled on zone
241- Another Worker intercepting request
242- Using dashboard preview (doesn't simulate transforms)
243
244### Common Error Codes
245
246| Code | Meaning |
247| ---- | -------------------------------------- |
248| 9401 | Invalid transformation options |
249| 9402 | Image too large |
250| 9403 | Request loop detected |
251| 9422 | Free tier limit exceeded (5,000/month) |
252| 9520 | Unsupported format |
253
254## Related Skills
255
256- `cloudflare-workers` - For serverless compute
257- `cloudflare-pages` - For full-stack apps
258- `cloudflare-r2` - R2 object storage