Localess

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.

ParameterTypeDescriptionExample
winteger, 1–8192Target width in pixels. A width above the source responds 302 to the source width — it never upscales.?w=800
hinteger, 1–8192Target height in pixels. Same rules as w.?h=600
fitstringHow 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
qinteger, 1–100Output 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
fstringOutput format: webp, jpeg, png, or avif. Without it, the stored format is kept.?f=webp
thumbnailflagFor 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)

whBehaviour
✓—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, and f are ignored.
  • Animated WebP or GIF with w, h, or f — all frames are resized or converted. Animations above 12 megapixels across all frames are rejected with 400; use thumbnail for those.
  • Animated WebP or GIF with thumbnail — first frame extracted, then w/h/f apply normally.
  • Video with w + thumbnail — frame extracted via FFmpeg, then resized; output defaults to image/webp.

Combine parameters with &:

https://my-space.web.app/api/v1/spaces/abc123/assets/<asset-id>?w=1200&f=avif

Original File and Download

Two routes serve the stored bytes with no transform at all. Neither accepts parameters — adding one returns 400.

RouteSDKServes
…/assets/<id>/originalassetOriginalLink() / resolveAssetOriginal()The file exactly as uploaded, displayed inline
…/assets/<id>/downloadassetDownloadLink() / 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=800

Returns 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=400

Returns the image at 400 px tall. Width scales proportionally.

Crop to exact dimensions

/api/v1/spaces/abc123/assets/<asset-id>?w=800&h=600

Returns 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=avif

Converts 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=avif

A 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

ApproachBest when
URL transformsYou upload once and serve at multiple sizes — responsive images, thumbnails, format variants
Pre-sized uploadsYou 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 formatRecommended ?f= valueReason
JPEG (photographic)avifConsistently smaller, at roughly 2.5× the encode time. WebP may be larger than the JPEG it replaces
PNG (photographic)avif or webpMuch better compression than lossless PNG for photos
PNG (transparency needed)avif or webpBoth support alpha
PNG (screenshots, UI)png with qPalette 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>.

On this page