Files and images
Uploading and organizing
Under Files: drag files onto the area or click Upload (up to 64 MB per file). Folders are only for organization – moving or renaming never changes a file’s URL. To move a file, drag it onto a folder on the left.
On the right for each file: name, alt text, dimensions, variants, copy URL, copy template tag, delete.
Cleaning up
After repeated imports or restructuring, images and CSS/JS files that nothing uses anymore are often left over. Clean up… (under Files and under CSS & JS) lists them – images with a preview, everything preselected. Deselect what should stay, then Delete selected; you are asked to confirm first. Deletion is permanent, including image variants and WebP versions.
A file counts as used if pages (HTML, Head, SEO fields), Snippets, CSS/JS, Collection entries, Workflows, Pens or REST sources refer to it – via its address (also an image variant or WebP version), via image(ID)/file(ID), an image or file field, as a website icon or preview image. CSS/JS counts as used if it is attached to a page or included via asset_url(ID); an unused stylesheet does not count as a use of the images in it. Just before deleting, the server checks again and leaves everything that has come into use in the meantime.
What can’t be detected are references from outside (other websites, newsletters pointing directly to
/media/…) and from old versions in the version history – if you reset a page to an old state, deleted images there won’t be found anymore. If in doubt, deselect.
Image variants and srcset
For JPEG and PNG, IllusionCMS automatically creates scaled-down versions 320, 640, 960, 1280 and 1920 px wide when uploading (only widths smaller than the original). This way browsers load only as much image as they need. GIF, WebP and SVG are stored unchanged.
This is how images get onto the page:
-
The Image button in the editor – inserts an
<img>withsrcset,sizes, width/height, alt text andloading="lazy"; for JPEG/PNG inside a<picture>with WebP versions (see below). -
Template tag – stays up to date when the alt text or file changes:
{{ image(12) }} {{ image(12, "(min-width: 900px) 50vw, 100vw") }} {{ image(12, "100vw", "hero-bild") }} -
File info for your own constructions:
{% with f=file(12) %} <div class="hero" style="background-image:url('{{ f.url }}')"></div> {% endwith %}
Setting sizes correctly: The value tells the browser how wide the image is displayed on the page. 100vw for full width, (min-width: 960px) 50vw, 100vw for an image that is half as wide from desktop up. The image dialog has presets.
Alt texts describe the image for screen readers and search engines. Maintain them in the file manager – image() takes them over automatically.
WebP and sizes via URL
For every JPEG and PNG – the original and all variants – there is automatically a WebP version, usually about half the size. image() and the image dialog therefore put the image into a <picture>: browsers with WebP support (all current ones) load the WebP file, all others the usual <img>:
<picture>
<source type="image/webp" srcset="/media/2026/10/foto-ab12-320w.jpg.webp 320w, …, /media/2026/10/foto-ab12.jpg.webp 1600w" sizes="100vw">
<img src="/media/2026/10/foto-ab12.jpg" srcset="…" sizes="100vw" width="1600" height="900" alt="…" loading="lazy" decoding="async">
</picture>
The WebP file is named like the image with .webp appended and is created on the first request (a one-time fraction of a second); after that it lives as a file next to the original – also for existing images, without you having to do anything. If an image is replaced (re-import), it is created anew.
For your own HTML and CSS there are URL parameters:
| URL | returns |
|---|---|
/media/…/foto.jpg?w=500 |
the smallest variant at least 500 px wide (here 640 px), otherwise the original |
/media/…/foto.jpg?format=webp |
the WebP version of the original |
/media/…/foto.jpg?w=500&format=webp |
both combined |
w always selects one of the fixed widths (320, 640, 960, 1280, 1920) – arbitrary sizes are not generated, so nobody can fill up the storage. In file(), the WebP srcset is under .webp_srcset. The static export contains the WebP files that are used.
Private files
A file can be private: visitors of the website don’t get to see it – /media/… answers them with “not found” (404), as if the file didn’t exist. This applies to the original, all image variants and WebP versions. Allowed to see it are:
- signed-in users – in the admin (session) and with an API token, read-only tokens included (
Authorization: Bearer …or?token=…), - anyone with a signed link.
This is meant for confidential PDFs, drafts or material you send to clients via a link.
Switching: Under Files, click the file and turn on Private on the right – it takes effect immediately. To upload as private right away, tick Private next to Upload. Private files show a lock with “Private” in the grid; the selection dialogs (insert image, link file) show a notice for them.
Signed links: For a private file, choose the validity below the switch (1 hour, 1 day, 7 days, 30 days) and click Copy link. The full address is then on the clipboard, and the message shows the expiry date. The link looks like this: /media/2026/10/offer-ab12.pdf?exp=…&sig=… – it is valid for the file including its variants and WebP versions and can neither be extended nor transferred to other files. Individual links cannot be revoked: signatures stay valid until they expire, even if you switch the file to public and back to private in between. So choose a short validity. Responses for private files are not cached (Cache-Control: private, no-store) and not indexed (X-Robots-Tag: noindex), and downloads do not count in the statistics.
Preview: In the preview of the page editor, with ?preview=1 and in preview links, private images still appear – image(), file() (.url, .srcset, .webp_srcset), site icon and preview image return signed addresses there (valid for about one to two hours). On the live page the addresses stay unsigned, so visitors don’t see the image. file(ID).private tells whether a file is private, e.g. to output a link only for public files:
{% with f=file(12) %}{% if not f.private %}<a href="{{ f.url }}">{{ f.name }}</a>{% endif %}{% endwith %}
Limitation: Only addresses from
image()/file()are signed. Paths written into the HTML by hand (<img src="/media/…">, also from the image dialog without Insert as template tag) stay as they are – the image is then missing in the preview. So use the template tag for private images (the image dialog preselects it for private files). The static export always leaves private files out.