You never configure hosting for your media. Uploading a file and publishing a page that uses it is the whole job: the resizing, the format negotiation, the streaming and the URLs are all decided for you at build time and at request time. This page is what that decision-making produces, so you can predict what a visitor gets — and, at the end, what a visitor who is not supposed to have your file could get anyway.
Delivery is not plan-gated. Everything here works identically on Free and on Enterprise.
Images: one upload, six widths
You upload a single image at its original size. The image CDN then serves it at any of six responsive widths, plus four fixed named sizes reserved for particular jobs. You never upload a second copy, and there is nothing to configure per image.
| Variant name | What it is for |
|---|---|
small | The narrowest responsive width — phones on slow connections |
medium | Phones and small tablets |
large | Tablets and small laptops |
xl | Most desktop displays |
xxl | Large and high-density displays |
original | The fallback, and the widest image ever served |
social | The image a link preview card uses — Leed points both the Open Graph and the Twitter card tags at it |
socialtiny | A registered small social size a template can ask for by name |
profile | A registered avatar size a template can ask for by name |
profiletiny | The small round avatar the built-in author and index templates use |
The exact pixel dimensions of each one live with the developer-facing mechanism, in the variant ladder — an uploader’s question is “what did Leed make from my file”, not “how many pixels wide is xl”.
The variant is the last segment of the image’s URL, and that is all that changes between them:
/cdn-cgi/imagedelivery/<account>/<image-id>/original
/cdn-cgi/imagedelivery/<account>/<image-id>/mediumNote that the path is on your own domain, not on a third-party image host. Your site’s worker proxies the CDN, so an image URL never leaks another company’s hostname into your markup and never asks a visitor’s browser to open a connection somewhere else.
What the build writes for you
Every eligible <img> in your rendered HTML is rewritten at build time to offer the whole ladder. You write the image once, in the editor or in a template; Leed adds the rest.
<!-- what your page contains -->
<img src="/cdn-cgi/imagedelivery/<account>/<image-id>/original"
alt="Sunrise over the harbour">
<!-- what the build publishes -->
<img src="/cdn-cgi/imagedelivery/<account>/<image-id>/original"
alt="Sunrise over the harbour"
srcset="/cdn-cgi/imagedelivery/<account>/<image-id>/small 320w,
/cdn-cgi/imagedelivery/<account>/<image-id>/medium 640w,
/cdn-cgi/imagedelivery/<account>/<image-id>/large 1280w,
/cdn-cgi/imagedelivery/<account>/<image-id>/xl 1920w,
/cdn-cgi/imagedelivery/<account>/<image-id>/xxl 2560w,
/cdn-cgi/imagedelivery/<account>/<image-id>/original 5120w"
sizes="100vw"
data-pristine="/cdn-cgi/imagedelivery/<account>/<image-id>/original">Three things in that output are worth knowing. sizes="100vw" is added only when the image does not already declare its own, so a template author who knows the image is half-width can say so and keep it. data-pristine holds the URL exactly as you wrote it, which is how the build can undo its own work when it needs to. And the src is left pointing at original, so a browser that ignores srcset entirely still gets a working image.
A declared width narrows the list. If the <img> carries a width attribute — which every image inserted through the editor does, because the editor knows the real dimensions — only the variants at or below that width are offered, so a 600 px image never invites a browser to download a 2560 px file. Widths above 5120 are clamped: 5120 px is the largest image Leed will ever serve. The exact emitted strings, including two long-standing quirks in how the declared width is appended, are on Image Variants and Responsive Images.
flowchart TD
UP["One original, uploaded once"] --> CDN["Image CDN can serve it<br/>at any of the six widths"]
CDN --> BLD["At build time: every image on the page"]
BLD --> SK{"Eligible for the rewrite?"}
SK -->|"No"| ASIS["Published exactly as authored"]
SK -->|"Yes"| RW["Add srcset and sizes=100vw,<br/>keep the original URL on data-pristine"]
RW --> CHK{"Is the URL a Leed image URL?"}
CHK -->|"No"| UNDO["Rewrite undone,<br/>original src restored"]
CHK -->|"Yes"| BR["Browser picks the width it needs"]
BR --> FMT["CDN negotiates AVIF or WebP<br/>per browser, from the same original"]
When the rewrite is skipped
Six conditions stop the rewrite, checked in this order. None of them is an error; each is a case where rewriting would make the page worse.
| Condition | Typical cause | Result |
|---|---|---|
data-responsiver="false" | An SVG asset placed from the CMS — Leed writes this attribute itself | Served exactly as authored |
No src and no data-src | A placeholder, or a template expression that resolved to nothing | Nothing to rewrite |
The image already has a srcset | You, or a helper, wrote your own responsive list | Yours is kept, untouched |
No src, but a data-srcset | A JavaScript lazy-loader carrying its own list | Yours is kept, untouched |
The src ends in .svg | A vector image | Vectors scale on their own; there is nothing to resize |
A data: URI with no data-src or data-srcset | An inline placeholder pixel with no real image behind it | Nothing to point at |
Two more exclusions sit outside that list. An <img> that is a direct child of <picture> is never touched at all, because declaring <picture> sources is an explicit statement that you are handling this yourself. And after the rewrite runs, Leed checks that the URL it just rewrote is actually one of its own image URLs — if it is not, the rewrite is undone: the original src is restored and the added srcset and sizes are removed.
My image is not responsive
Walk the six conditions above in order against the published HTML, then the two exclusions. In practice one cause dominates: the image is not a Leed asset. A file committed into your repository under static/ and referenced by path has no variant ladder behind it, so the build adds a srcset and then takes it straight back off. The fix is not a setting — it is to upload the image as an asset and place it from the library, which is the delivery argument for the asset manager rather than a housekeeping one. Uploading Images covers getting it in there.
Formats: chosen per browser, not by you
From the single original you uploaded, the image CDN negotiates the best format each browser will accept — AVIF or WebP where they are supported, the original format where they are not. There is no per-image setting, no quality dial and nothing to choose, which also means there is nothing to get wrong. A visitor on a current browser typically receives a materially smaller file than the JPEG or PNG you uploaded, at the width their viewport actually needs.
Video: adaptive playback
Video is served by a streaming player rather than as a file. It adapts quality to the viewer’s connection, so a visitor on a train gets a lower bitrate instead of a stall, and it honors the choices you made on the asset.
The published embed carries controls, muted and loop explicitly, adds autoplay only when you have switched it on, and adds a poster parameter pointing at the exact frame you chose with Set Thumbnail from Current Position. Full-screen is permitted by an attribute on the embed rather than a URL parameter. Where those checkboxes are and what each does is on Video, Audio and Document Assets.
Audio and documents: the /f/ URL
Audio files and documents are not served from the image CDN or from the streaming platform. They are served through your own site, at a URL of this shape:
https://your-domain.com/f/9f3c1a72-4c8e-4a6b-9f21-6d0c7b5e2a84/quarterly-report.pdfThe middle segment is the asset’s id and it is the only part used for the lookup. The last segment is a display name for the browser — it decides what the file is called when someone saves it, and it appears in analytics, and that is the whole of its job. Quotes, angle brackets and ampersands are stripped from it and runs of spaces are collapsed, so a file named Q3 "final" <v2>.pdf is offered as Q3 final v2.pdf.
Two consequences follow, and both are useful:
- The link follows the asset, not the file. Replacing the file behind an asset updates every existing link at once — on pages, in old emails, in someone’s bookmarks. You never chase down references.
- Renaming never breaks anything. Because the filename is display-only, changing it changes what the browser calls the download and nothing else.
If the asset does not exist — wrong id, or an asset that has been deleted — the request does not error. The visitor is redirected to your site’s /404 page, which means a deleted asset degrades into a normal missing-page experience rather than a broken download. The file itself is streamed back with the content type it was stored with, so a PDF usually opens in a browser tab; the copy-and-paste snippet on Asset Details and Usage adds a download attribute when you want a save instead.
What is protected, and what is not
Start with what is true. Your files are reachable only through your own domain’s /f/ path, served by your own site’s worker. A deleted asset stops resolving immediately, everywhere, because the lookup goes through the asset record. Download names are sanitized before they are handed to a browser. And nothing about an asset’s URL exposes your storage account or lets anyone enumerate your library.
Gating a download behind a form is a different mechanism and does work: the visitor fills in the form, and the file link is delivered to them by email. That gates the distribution of the URL, not the URL itself — see Response Emails and Gated Downloads.
Download links in email
A file link in an email Leed sends for you is not a bare /f/ URL. It is a per-recipient address of the form /e/f/… that records the click against that specific contact, updates their activity, and then redirects to the /f/ URL. That is how you get “who downloaded the pricing sheet” out of a campaign.
It is attribution, not access control: the address it redirects to is the same public /f/ URL as everyone else’s, and forwarding the email forwards a working link — which also means a forwarded click is attributed to the original recipient.
What Leed records, and where you can see it
Every non-preview request for a /f/ URL is stored as a file-download event carrying the asset id, the time and the referrer that sent the visitor. A session that begins with a download — someone arriving straight at a PDF from a search result, with no page view first — is tagged internally as having started that way.
Now the honest part: there is no downloads report today. The events are recorded and retained, but nothing surfaces them — there is no Know widget, no downloads metric, no per-asset count, and the Analytics tab on an asset’s right rail is a fixed placeholder rather than a view of these numbers. A session that started with a download even shows in Engage as Direct, because nothing reads the tag. It is collected, not reported; the gap is listed in Known Limitations.
Video and audio engagement is the exception and does have a real report — plays, time viewed, drop-off, on Growth and above — in Media Engagement Analytics.
For the rest of what a visitor’s browser receives from a published page — the response headers, what is cached and for how long — see Headers, Caching and Security, and for the whole picture of a published page, What Your Visitors Get. The social variants named above are what a link preview actually renders, which is the subject of Social Cards and Structured Data.