Image Transforms
Resize, reformat, and optimize images on demand by appending URL parameters to any Localess asset URL — no extra service required.
Localess asset URLs support on-demand image transformation via query parameters. Append a parameter to any asset CDN URL to get back a resized, reformatted, or quality-adjusted image — without uploading multiple size variants and without a third-party image CDN.
This is useful for responsive images, thumbnails, and format optimization. The transformation happens server-side and the result is cached at the CDN edge.
URL Parameter Reference
Pass these as the params argument of client.assetLink() or resolveAsset() — the SDK builds the query string and validates the values.
| Parameter | Type | Description | Example |
|---|---|---|---|
w | integer, 1–8192 | Target width in pixels. A width above the source responds 302 to the source width — it never upscales. | ?w=800 |
h | integer, 1–8192 | Target height in pixels. Same rules as w. | ?h=600 |
fit | string | How the image fills the box when both w and h are set: cover (default), contain, inside, outside, or fill. Ignored with a single dimension. | ?fit=inside |
q | integer, 1–100 | Output quality. Omitted, each encoder uses its own default: JPEG and WebP 80, AVIF 50. On PNG output an explicit q switches to 8-bit palette quantisation (lossy); without it PNG stays lossless. | ?q=70 |
f | string | Output format: webp, jpeg, png, or avif. Without it, the stored format is kept. | ?f=webp |
thumbnail | flag | For animated WebP/GIF: extracts the first frame before resizing. For video with w: extracts a frame with FFmpeg; output defaults to WebP. | ?thumbnail |
Values outside these ranges, fractions, or unknown values are rejected with 400 — and that 400 is cached for an hour. The SDK throws a TypeError for an invalid w, h or q before the URL is built. Round computed widths with Math.round(): each distinct value is a separate cache entry.
Resize Behaviour (w / h)
w | h | Behaviour |
|---|---|---|
| ✓ | — | Scale to width, height auto — aspect ratio preserved, no crop |
| — | ✓ | Scale to height, width auto — aspect ratio preserved, no crop |
| ✓ | ✓ | Governed by fit — the default cover fills the exact box and crops the overflow; inside fits within it without cropping |
| — | — | No resize — but still images (JPEG, PNG, WebP, AVIF) are still re-encoded at the default quality. For the uploaded bytes, use the original link |
When both w and h exceed the source, the box is shrunk proportionally, so its shape — and the fit result — stay the same.
Special Cases
- SVG, GIF, video, and animations — a URL with no parameters serves the stored file as is.
- SVG — always passed through;
w,h, andfare ignored. - Animated WebP or GIF with
w,h, orf— all frames are resized or converted. Animations above 12 megapixels across all frames are rejected with400; usethumbnailfor those. - Animated WebP or GIF with
thumbnail— first frame extracted, thenw/h/fapply normally. - Video with
w+thumbnail— frame extracted via FFmpeg, then resized; output defaults toimage/webp.
Combine parameters with &:
https://my-space.web.app/api/v1/spaces/abc123/assets/<asset-id>?w=1200&f=avifOriginal File and Download
Two routes serve the stored bytes with no transform at all. Neither accepts parameters — adding one returns 400.
| Route | SDK | Serves |
|---|---|---|
…/assets/<id>/original | assetOriginalLink() / resolveAssetOriginal() | The file exactly as uploaded, displayed inline |
…/assets/<id>/download | assetDownloadLink() / resolveAssetDownload() | The same bytes as an attachment, so the browser saves them. Non-ASCII file names are preserved |
The former ?download parameter was removed in the current major version and is now rejected with 400.
Examples
Resize to a fixed width
/api/v1/spaces/abc123/assets/<asset-id>?w=800Returns the image at 800 px wide. Height scales proportionally to preserve the aspect ratio.
Resize to a fixed height
/api/v1/spaces/abc123/assets/<asset-id>?h=400Returns the image at 400 px tall. Width scales proportionally.
Crop to exact dimensions
/api/v1/spaces/abc123/assets/<asset-id>?w=800&h=600Returns an 800×600 image using the default fit=cover — the image is scaled to fill the box and the overflow is trimmed. Use this for fixed-size slots like hero banners. Add &fit=inside to fit the whole image within the box without cropping; the output may then be smaller than the box, which usually suits CMS thumbnails.
Convert the format
/api/v1/spaces/abc123/assets/<asset-id>?f=avifConverts to AVIF at the encoder's default quality. AVIF is consistently smaller than JPEG; WebP can come out larger than the JPEG it replaces on grainy or textured images, so measure your own assets before standardising on it.
Responsive thumbnail
/api/v1/spaces/abc123/assets/<asset-id>?w=400&f=avifA compact, web-optimized version of a full-size image — suitable for article cards and preview grids.
Using Transforms in Code
Pass the parameters as an object rather than appending a query string by hand — the SDK validates them and produces a stable parameter order, so equal requests share a cache entry.
@localess/client
import { localessClient } from '@localess/client';
const client = localessClient({ origin: 'https://my-space.web.app', spaceId: 'abc123', token });
client.assetLink(content.data.heroImage);
// → https://my-space.web.app/api/v1/spaces/abc123/assets/<asset-id>
client.assetLink(content.data.heroImage, { w: 1200, f: 'avif' });
// → https://my-space.web.app/api/v1/spaces/abc123/assets/<asset-id>?w=1200&f=avif@localess/react
import { type ContentAsset, resolveAsset } from '@localess/react';
function HeroImage({ image, alt }: { image: ContentAsset; alt: string }) {
return (
<img
src={resolveAsset(image, { w: 1200, f: 'avif' })}
srcSet={[400, 800, 1200].map((w) => `${resolveAsset(image, { w, f: 'avif' })} ${w}w`).join(', ')}
sizes="(max-width: 768px) 100vw, 1200px"
alt={alt}
/>
);
}@localess/angular — automatic with NgOptimizedImage
When you use provideLocaless(), Angular's NgOptimizedImage (ngSrc) directive uses the Localess image loader for Localess asset URLs. It adds each requested width to the generated srcset entries, so no manual width handling is needed. Other parameters — q, f, fit, thumbnail — go through [loaderParams]:
<img
ngSrc="{{ data.image | llAsset }}"
width="800"
height="600"
[loaderParams]="{ f: 'avif' }"
alt="Hero image"
/>The height Angular derives from the declared aspect ratio is deliberately not sent: sending both dimensions would switch the API to a fit crop whenever the declared ratio differs from the source. To request a box, pass h (and optionally fit) in loaderParams.
URL Transforms vs Uploading Pre-Sized Assets
| Approach | Best when |
|---|---|
| URL transforms | You upload once and serve at multiple sizes — responsive images, thumbnails, format variants |
| Pre-sized uploads | You need pixel-perfect control over cropping, or you have assets that are already optimized at a fixed size (icons, logos) |
For most editorial content (blog images, product photos, hero banners) URL transforms are the right default. Upload the highest-quality version of an image once, then let Localess handle resizing and format conversion at request time.
Pre-sized uploads make sense for:
- Art-directed crops (different composition at mobile vs desktop)
- SVG and other vector formats that do not benefit from raster transforms
When the exact uploaded bytes matter — print, legal documents, archival — keep the single upload and link it with assetOriginalLink(); see Original File and Download.
Format Recommendations
| Source format | Recommended ?f= value | Reason |
|---|---|---|
| JPEG (photographic) | avif | Consistently smaller, at roughly 2.5× the encode time. WebP may be larger than the JPEG it replaces |
| PNG (photographic) | avif or webp | Much better compression than lossless PNG for photos |
| PNG (transparency needed) | avif or webp | Both support alpha |
| PNG (screenshots, UI) | png with q | Palette quantisation — roughly a third of the size, but lossy |
| Already WebP | — | Add ?f=avif if your audience supports it |
| Animated GIF/WebP | — | Resized with w/h; add ?thumbnail for a still first frame |
Check browser support for your target audience before relying on WebP or AVIF exclusively. For broad compatibility, serve AVIF with a WebP and JPEG fallback using <picture> and <source>.