Media Delivery
Render Amondo media at the right size on web, iOS and Android using delivery URL templates.
Overview
Every CloudinaryMedia object in the API exposes a delivery field with server-built URL templates for sized delivery. Instead of downloading the full-size publicUrl, substitute a width into a template and fetch a variant that matches the size you actually render. This gives smaller downloads, automatic format negotiation (WebP/AVIF for images, best codec for video) and automatic quality tuning.
media {
publicUrl
width
height
delivery {
__typename
... on ImageDelivery {
image { urlTemplate widths }
avatar { urlTemplate widths }
}
... on VideoDelivery {
video { urlTemplate widths }
poster { urlTemplate widths }
}
}
}The field is available on both endpoints (gql.amondo.com and pub.amondo.com) wherever CloudinaryMedia appears — tile media, author avatars, form images, backgrounds and so on.
Template fields
delivery is a union: ImageDelivery for IMAGE media, VideoDelivery for VIDEO media. Switch on __typename.
ImageDelivery
image
Rendering the image at layout size
ImageDelivery
avatar
Small round author avatars (fixed widths 20, 30, 40, 60, 80)
VideoDelivery
video
Video playback at layout size
VideoDelivery
poster
JPG still of the first video frame — placeholder before playback
Each of these is a DeliveryTemplate:
urlTemplate
String!
Absolute URL containing the literal token {w}
widths
[PositiveInt!]!
Valid substitutions for {w}, ascending
Example urlTemplate values:
delivery is null for passthrough media (Instagram CDN, S3, base64, uploads still processing). Always handle this case: render publicUrl as-is.
Choosing a width
To build a URL:
Take the width the media is rendered at, in layout units (CSS px, iOS points, Android dp).
Multiply by the device pixel ratio, clamped to 2 — beyond 2× the extra pixels are not worth the bytes.
Pick the smallest
widthsentry ≥ that product, or the largest entry if none is.Substitute it for the
{w}token inurlTemplate.
Only the listed widths are supported — do not substitute arbitrary values.
The widths ladder runs in 100px steps and is capped at the source media width (rounded up to the next 100) and at 2000 — e.g. a 1080px-wide source yields [100, 200, …, 1100]. The ladder is per-media; always read it from the response.
Scaling and crop rules
Delivery URLs scale, they never crop. Every template uses c_limit:
Aspect ratio is always preserved. The returned file is the source scaled down so its width fits
{w}; height follows the source aspect ratio.Never upscaled. If
{w}exceeds the source width you get the source size. Don't assume the returned file is exactly{w}pixels wide.Never cropped server-side. Fitting media into a box of a different aspect ratio (a square grid cell, a 9:16 story) is always done by the renderer.
Tiles tell you which fit the editor chose. MediaTileAttributes (and the other tile attribute types) carry two TileCrop settings:
crop— how media displays in the grid:FILLcrops to fill the cell,FITletterboxes.cropFrame— the same choice for the expanded frame view.
Map FILL/FIT to your platform's fit modes:
TileCrop
CSS
UIKit
SwiftUI
Android View
Jetpack Compose
FILL
object-fit: cover
.scaleAspectFill + clipsToBounds
.scaledToFill().clipped()
centerCrop
ContentScale.Crop
FIT
object-fit: contain
.scaleAspectFit
.scaledToFit()
fitCenter
ContentScale.Fit
Uploaded Cloudinary media is ingested with a maximum 4K resolution preset. Larger source uploads may be normalised at ingest before delivery templates are generated.
Web — CSS only
No JavaScript needed: expand the ladder into srcset and let the browser pick, then crop with object-fit.
Generate the srcset string directly from widths:
For background-image, use background-size: cover (FILL) or contain (FIT).
With srcset the browser applies the full device pixel ratio (3× on many phones) and may pick one ladder step higher than the clamp-to-2 rule would. Every listed width is valid, so this is fine. If you want the bandwidth-optimal 2× cap, select the width yourself with the JS helper above.
iOS
Select the width from the view's point size and screen scale, then let the image view crop:
UIKit:
SwiftUI:
Android
View widths are already in physical pixels; rescale them so densities above 2× don't fetch oversized files:
Views (with Coil or Glide):
Jetpack Compose:
Videos and posters
For VideoDelivery, pick widths for video and poster with the same algorithm, sized to the player:
Show the
posterURL as the placeholder (<video poster="…">,AVPlayerLayeroverlay, Compose placeholder) while the video loads. It is a JPG of the first frame at low quality — cheap and instant.Feed the
videoURL to your player. Format and codec are negotiated automatically viaf_auto.
Fallback
Code the delivery == null path from day one — it is not an edge case. Media served from Instagram's CDN, direct S3 objects and uploads that are still processing all return null. In that case render publicUrl unchanged (it may be full-size) with the same client-side FILL/FIT treatment.
Full example
Query a published imprint on pub.amondo.com (no auth) and render its media tiles:
Example media payload:
Rendering this tile in a 400 CSS px column on a 3× phone: target = 400 × min(3, 2) = 800 → pick w_800. The tile's crop is FILL, so the image gets object-fit: cover.
Last updated

