Configuring Cloudflare Image Resizing URL parameters

The /cdn-cgi/image/<options>/<source> URL is deceptively simple: a comma-separated option list, then the path to your master. But each option interacts with the others, and a wrong fit or a missing format=auto quietly ships the wrong bytes. This guide — part of Cloudflare Image Resizing and Polish within CDN & Edge Media Delivery — walks every option in the string, gives one fully annotated worked example, and shows the exact curl that proves the edge did what you asked.

Prerequisite checklist

Anatomy of the URL

The URL has three fixed segments, and getting their boundaries right matters more than any single option. The prefix triggers interception, the middle segment carries the options, and the tail names the master. The options are part of the path, never a query string.

Anatomy of a /cdn-cgi/image/ URL A single URL split into three labelled segments. The first segment /cdn-cgi/image/ is the edge-interception prefix. The middle segment width=640,fit=cover,quality=75,format=auto is the comma-separated options list, each option annotated. The final segment /media/hero.jpg is the origin path of the master image. A caption warns that options must be in the path, not a query string. /cdn-cgi/image/ width=640,fit=cover,quality=75,format=auto /media/hero.jpg interception prefix options (comma-separated) origin master path target width (px) crop mode perceptual quality negotiate AVIF/WebP from Accept Options live in the PATH — ?width=640 as a query string is ignored and the source is served untouched.

The option string, parameter by parameter

Options are a comma-separated list with key=value pairs, placed between /cdn-cgi/image/ and the source path. Order does not matter; unknown keys are ignored.

Sizing: width, height, dpr, fit

  • width (w) — target width in device pixels. This is the primary lever; it is what actually shrinks payloads. Bound it to your breakpoint set.
  • height (h) — target height. With only one of width/height set, the other is derived from the aspect ratio.
  • dpr — device-pixel-ratio multiplier applied on top of width. width=320,dpr=2 produces a 640-pixel image intended to paint into a 320 CSS-pixel slot on a 2× display.
  • fit — how the image is fitted to the width×height box:
    • scale-down — fit within the box, never enlarge. Preserves aspect ratio. Safest default.
    • contain — fit within the box, may enlarge. Preserves aspect ratio.
    • cover — fill the box, cropping overflow. Preserves aspect ratio; pair with gravity.
    • crop — fill and hard-crop to the exact box dimensions.
    • pad — fit within the box and pad the remainder with background.

Format and quality: format, quality

  • format=auto — negotiate AVIF/WebP/JPEG from the request Accept header. This is what makes one URL serve the right codec to every client. Omit it and you get the source format for everyone.
  • quality (q) — perceptual quality 1–100. Around 75 is a strong photographic default; drop to 55–65 for thumbnails, raise to 85+ for detailed hero art.

Cropping and focus: gravity, background

  • gravity — focal point for cover/crop. Accepts auto (saliency detection), a side (left, right, top, bottom), or normalized coordinates like 0.5x0.2 (horizontal×vertical, 0–1).
  • background — fill colour for fit=pad or for flattening transparency when producing a format without an alpha channel. Accepts CSS colours or %23RRGGBB (URL-encoded hex).

Detail and robustness: sharpen, metadata, onerror, anim

  • sharpen — 0–10 unsharp-mask strength. Downscaling softens edges; sharpen=1 recovers crispness on photos, higher values over-sharpen.
  • metadatanone (default, strips EXIF), copyright (keeps only copyright), or keep (retains all EXIF, larger files).
  • onerror — what to do if the master cannot be fetched or resized. redirect serves the original source instead of an error, so a broken transform degrades to the unoptimized image rather than a broken icon.
  • animtrue preserves animation frames (animated WebP/GIF); anim=false collapses an animation to its first frame, useful for generating a static poster.

Worked example — one fully annotated URL

The following URL derives a 640-pixel-wide, cover-cropped, negotiated variant from a portrait master, keeping the subject’s face in frame and degrading gracefully if the master is missing:

<!--
  Break the option string down comma by comma:
    width=640      target 640 device pixels wide (a real breakpoint)
    height=800     target height; with width this defines a 4:5 box
    fit=cover      fill the whole 640x800 box, cropping overflow
    gravity=0.5x0.3 keep the crop centred horizontally, biased UP toward
                   the face (0.3 vertical) rather than the geometric centre
    quality=75     perceptual quality target for photographic content
    format=auto    negotiate AVIF/WebP/JPEG from the request Accept header
    sharpen=1      restore edge crispness lost when downscaling the master
    metadata=none  strip EXIF to shave bytes and remove location data
    onerror=redirect if the master 404s or fails, serve the original source
                   instead of a broken image
  The trailing /media/portraits/anaïs-master.jpg is the ORIGIN path of the
  master. Note the source is URL-relative to the same zone.
-->
<img
  src="/cdn-cgi/image/width=640,height=800,fit=cover,gravity=0.5x0.3,quality=75,format=auto,sharpen=1,metadata=none,onerror=redirect/media/portraits/anais-master.jpg"
  width="640" height="800"
  alt="Studio portrait, cropped to the subject's face"
  loading="lazy" decoding="async">

Warning: the option string is before the source path, not a query string. A frequent mistake is writing /media/img.jpg?width=640 — Cloudflare Image Resizing ignores query-string options entirely and serves the untouched source. The options must sit in the path segment right after /cdn-cgi/image/.

Warning: if you pass background as a hex colour, URL-encode the # as %23 (for example background=%23ffffff). A literal # starts the URL fragment and the parameter is silently dropped.

Verification

Confirm the negotiated format and that Resizing ran

# Simulate a Chrome request (advertises AVIF + WebP). A correct transform
# returns content-type: image/avif and a cf-resized header. The cf-resized
# header appears ONLY when Image Resizing processed the request — its
# absence means the option string was ignored (feature off, or query-string
# mistake) and the source was served untouched.
curl -sI -H 'Accept: image/avif,image/webp,*/*;q=0.8' \
  'https://yoursite.com/cdn-cgi/image/width=640,height=800,fit=cover,quality=75,format=auto/media/portraits/anais-master.jpg' \
  | grep -iE 'content-type|cf-resized|cf-cache-status'
# Expected:
#   content-type: image/avif
#   cf-resized: internal=ok/…
#   cf-cache-status: HIT

Confirm the fallback tier for Safari 14

# Safari 14 advertises WebP but not AVIF. The same URL must return WebP here,
# proving format=auto negotiated correctly rather than forcing one codec.
curl -sI -H 'Accept: image/webp,image/*,*/*;q=0.8' \
  'https://yoursite.com/cdn-cgi/image/width=640,height=800,fit=cover,quality=75,format=auto/media/portraits/anais-master.jpg' \
  | grep -i 'content-type'
# Expected: content-type: image/webp

Confirm the actual delivered dimensions

# Download the transformed bytes and read the intrinsic size, proving the
# resize happened (not just a re-encode at native resolution). identify ships
# with ImageMagick; use `file` if you only need the format.
curl -s -H 'Accept: image/avif' \
  'https://yoursite.com/cdn-cgi/image/width=640,height=800,fit=cover,format=auto/media/portraits/anais-master.jpg' \
  -o /tmp/variant.avif
identify -format '%wx%h %m\n' /tmp/variant.avif
# Expected: 640x800 AVIF

Common mistakes

1. Options placed as a query string

Symptom: the full-size source is served; cf-resized is absent. Cause: options written as ?width=640 instead of in the path. Fix: move them into the path: /cdn-cgi/image/width=640,format=auto/media/img.jpg.

2. format=auto omitted

Symptom: Chrome receives JPEG even though AVIF was expected. Cause: without format=auto, Resizing keeps the source format. Fix: always include format=auto unless you deliberately want a fixed codec.

3. Continuous widths from client JavaScript

Symptom: cache hit rate near zero; transform bill climbs. Cause: passing window.innerWidth (751, 752, 753…) mints a new variant per pixel. Fix: snap to a fixed breakpoint set before building the URL — the clamp pattern shown in Cloudflare Image Resizing and Polish.

4. fit=cover with no gravity on portraits

Symptom: faces cropped off the top of tall images. Cause: cover defaults to a centre crop. Fix: set gravity to auto or explicit coordinates biased toward the subject.

5. Upscaling with fit=contain

Symptom: small masters look soft and blocky at large width. Cause: contain enlarges past the master’s intrinsic size. Fix: use fit=scale-down so the edge never upscales beyond the source resolution.