Image delivery and transformation APIs
Image delivery and transformation APIs
TL;DR
- Append query parameters (?width=, ?format=webp, ?quality=) to any Contentstack asset URL for on-the-fly image transformation -- no build step or processing pipeline needed.
- Use ?auto=webp as a baseline optimization; it serves WebP to supporting browsers and falls back automatically, reducing payload by 25-35%.
- Always set explicit width and height on <img> elements and use loading="lazy" for below-fold images to protect LCP and CLS scores.
Images account for the majority of page weight on most websites. Contentstack provides a dedicated image delivery service with URL-based transformations that let you resize, crop, reformat, and optimize images without a separate image processing pipeline. Mastering these transformations is the difference between a site that scores well on Core Web Vitals and one that does not.
This lesson uses product images from Veda: The Revival Collection (jewelry e-commerce) as the running example.
Image delivery URL structure
When you upload an asset to Contentstack, it is served through Contentstack's image delivery CDN. The base URL follows this pattern:
https://images.contentstack.io/v3/assets/{stack_api_key}/{asset_uid}/{upload_uid}/{filename}For example, a product photo might have this URL:
https://images.contentstack.io/v3/assets/{stack_api_key}/{asset_uid}/matrix-link-bracelet.jpgThis URL is what appears in the url property of an asset object when you fetch entries through the Delivery API. Every image uploaded to Contentstack gets a unique, globally accessible URL on this CDN.
For EU and Azure regions, the host differs:
- NA: https://images.contentstack.io
- EU: https://eu-images.contentstack.com
- Azure NA: https://azure-na-images.contentstack.com
- Azure EU: https://azure-eu-images.contentstack.com
Common pitfall:
Serving the original full-resolution image (e.g., 4000px wide) when the rendered size is 800px wastes bandwidth and tanks your Largest Contentful Paint score -- always match ?width= to the rendered size.
The key insight is that transformations are applied by appending query parameters to this URL. No server-side processing step is needed in your application. The CDN handles transformation, caching, and delivery.
URL-based transformation parameters
Contentstack's Image Delivery API accepts query parameters that transform the image on the fly. The transformed result is cached at the CDN edge, so subsequent requests for the same transformation are served from cache.
Resizing with width and height
Scale an image to specific dimensions:
https://images.contentstack.io/v3/assets/.../matrix-link-bracelet.jpg?width=400&height=300
You can specify one dimension and let the other scale proportionally:
// Scale to 600px wide, maintain aspect ratio ?width=600 // Scale to 400px tall, maintain aspect ratio ?height=400
Specifying both dimensions without a fit mode may distort the image. Use the fit parameter to control how the image adapts.
Format conversion with format
Convert images to modern compressed formats for smaller network file sizes:
// Convert to WebP ?format=webp // Convert to AVIF (where supported) ?format=avif // Let Contentstack choose the best format based on the Accept header ?auto=webp
The auto=webp parameter is particularly useful. It inspects the browser's Accept header and serves WebP to browsers that support it, falling back to the original format for others. This single parameter can reduce image payload by 25-35% for most browsers without any client-side logic.
Quality control with quality
Reduce file size by adjusting compression quality (1-100):
// Good balance of quality and file size for product thumbnails ?quality=75 // Higher quality for hero images where detail matters ?quality=90
For JPEG and WebP formats, quality values between 70 and 85 provide a good balance. Below 60, compression artifacts become visible on product photography. For PNG, the quality parameter controls the compression level safely without introducing artifacts.
Cropping with crop
Extract a specific region of the image:
// Crop to a 400x400 region starting at position (100, 50) ?crop=400,400,x100,y50
The crop parameter accepts width,height,x{offset},y{offset} format profiles. This is useful for creating square thumbnails from rectangular product photos.
Fit modes with fit
When you specify both width and height, the fit parameter controls how the image fills the target dimensions:
// Scale down to fit within the bounds, preserving aspect ratio ?width=400&height=400&fit=bounds // Crop to fill the exact dimensions ?width=400&height=400&fit=crop
Available fit modes:
| Mode | Behavior |
| bounds | Scales down to fit within the specified width and height. The image may be smaller than the target on one axis. |
| crop | Scales and crops to fill the exact dimensions. Parts of the image may be trimmed. |
Trim with trim
Remove uniform borders or whitespace from product images:
// Trim 20px from all sides ?trim=20,20,20,20
The format is configured as trim=top,right,bottom,left. This is useful for product catalog images that have inconsistent whitespace around the product.
Combining parameters
Parameters can be combined in a single URL string. The CDN processes them sequentially in order and caches the final result:
https://images.contentstack.io/v3/assets/.../matrix-link-bracelet.jpg?width=800&height=600&fit=crop&format=webp&quality=80
This single URL delivers an 800x600 cropped WebP image at 80% quality. No build step, no image processing library, no lambda function. The CDN handles it.
Building responsive image srcsets
Modern responsive design requires serving different image sizes for different viewport widths. Contentstack's URL-based transformations make this straightforward by parameterizing the width.
The srcset attribute approach
<img src="https://images.contentstack.io/v3/assets/.../product.jpg?width=800&auto=webp&quality=80" srcset="
https://images.contentstack.io/v3/assets/.../product.jpg?width=400&auto=webp&quality=80 400w,
https://images.contentstack.io/v3/assets/.../product.jpg?width=800&auto=webp&quality=80 800w,
https://images.contentstack.io/v3/assets/.../product.jpg?width=1200&auto=webp&quality=80 1200w,
https://images.contentstack.io/v3/assets/.../product.jpg?width=1600&auto=webp&quality=80 1600w
" sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw" alt="Matrix Link Bracelet" width="800" height="600">The browser selects the most appropriate image size based on the viewport width and device pixel ratio. You generate the URLs in code by varying the width parameter.
A helper function for srcset generation
Rather than constructing URLs manually, building a utility function:
interface ImageTransformOptions {
quality?: number;
format?: "webp" | "avif" | "jpg" | "png";
fit?: "bounds" | "crop";
height?: number;
}
function buildImageUrl(
baseUrl: string,
width: number,
options: ImageTransformOptions = {}
): string {
const params = new URLSearchParams();
params.set("width", String(width));
if (options.quality) params.set("quality", String(options.quality));
if (options.format) params.set("format", options.format);
if (options.fit) params.set("fit", options.fit);
if (options.height) params.set("height", String(options.height));
if (!options.format) params.set("auto", "webp");
return `${baseUrl}?${params.toString()}`;
}
function buildSrcSet(
baseUrl: string,
widths: number[],
options: ImageTransformOptions = {}
): string {
return widths
.map((w) => `${buildImageUrl(baseUrl, w, options)} ${w}w`)
.join(", ");
}
// Usage with a product entry from Contentstack
const product = await fetchProduct("matrix-link-bracelet");
const imageUrl = product.media?.[0]?.url;
const srcset = buildSrcSet(imageUrl, [400, 800, 1200, 1600], {
quality: 80,
fit: "crop",
height: 600,
});This utility works with any asset URL from Contentstack. It avoids string concatenation bugs and makes it easy to enforce consistent quality and format settings across the application.
Lazy loading patterns with Contentstack image URLs
Lazy loading defers off-screen image loading until the user scrolls near them. Combined with Contentstack transformations, you can serve a tiny placeholder followed by the full image asset.
Native lazy loading
The simplest approach uses the browser's native loading attribute:
<img src="https://images.contentstack.io/v3/assets/.../product.jpg?width=800&auto=webp&quality=80" loading="lazy" alt="Pixel Stud Earrings" width="800" height="600">
For above-the-fold images (hero images, first visible product), omit loading="lazy" or set loading="eager" to ensure they load immediately.
Low-quality image placeholder (LQIP) pattern
Serve an extremely small version as a placeholder that loads instantly, then swap in the full image:
// Tiny blurred placeholder - loads in ~1-2 KB
const placeholderUrl = buildImageUrl(imageUrl, 40, {
quality: 30,
format: "webp",
});
// Full resolution product image
const fullUrl = buildImageUrl(imageUrl, 800, {
quality: 80,
});<img src="https://images.contentstack.io/.../product.jpg?width=40&quality=30&format=webp" data-src="https://images.contentstack.io/.../product.jpg?width=800&auto=webp&quality=80" class="product-image lazyload" alt="Circuit Collar Necklace" width="800" height="600" style="filter: blur(10px); transition: filter 0.3s;">
An intersection observer or a utility swaps data-src into src when the image enters the viewport. The CSS blur transition provides a smooth reveal.
Optimizing Core Web Vitals with proper image sizing
Google's Core Web Vitals - particularly Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS) - are directly impacted by image handling.
Reducing LCP with right-sized images
LCP measures when the largest visible element finishes rendering. For product pages, this is usually the hero product image. To minimize LCP:
- Serve the correct size: A 4000px image displayed at 800px wastes bandwidth. Use ?width=800 to match the rendered size.
- Use modern formats: ?auto=webp reduces file size by 25-35% compared to legacy JPEG arrays.
- Set appropriate quality: ?quality=80 is visually indistinguishable from 100 for most product photos, at half the raw payload file size.
- Preload the LCP image: Add a <link rel="preload"> for the hero image so the browser starts fetching it before it discovers the
tag in the HTML.
Preventing CLS with explicit dimensions
CLS penalizes layout shifts caused by images loading without reserved space. Always set width and height attributes on elements:
<img src="https://images.contentstack.io/.../product.jpg?width=800&auto=webp&quality=80" width="800" height="600" alt="Data Drop Earrings">
The browser uses the width/height ratio to reserve layout space before the image loads. If you use CSS to make images responsive (width: 100%; height: auto;), the aspect ratio is preserved from the HTML attributes, preventing layout shifts.
Combining techniques for a product card
Here is a complete example building a product card component with optimized images:
interface Product {
title: string;
price: number;
media: Array<{ url: string; title: string }> | null;
url: string;
}
function renderProductCard(product: Product): string {
const baseUrl = product.media?.[0]?.url ?? "";
const srcset = buildSrcSet(baseUrl, [300, 600, 900], {
quality: 80,
fit: "crop",
height: 400,
});
const defaultSrc = buildImageUrl(baseUrl, 600, {
quality: 80,
fit: "crop",
height: 400,
});
return `
`;
}This card serves right-sized, WebP-converted, quality-optimized images with proper responsive breakpoints, lazy loading for off-screen cards, and explicit dimensions to prevent layout shift.
When not to use URL transformations
Contentstack's image transformations cover most use cases, but know their structural operational limits:
- Complex compositing: Overlaying dynamic text, complex watermarks, or combining multiple image binaries requires a dedicated image microservice infrastructure.
- SVG manipulation: SVG files are delivered as-is as clean vectors. Transformation parameters apply exclusively to raster formats (JPEG, PNG, WebP, GIF).
- Video thumbnails: Contentstack's image service handles images only. Video poster frames need separate automated asset processing.
- Extremely high-resolution print assets: The service is optimized for web delivery. For print-resolution assets, download the original and process locally.
Exercise: construct image URLs for a responsive product card
Using a product entry with an image asset from Contentstack, follow these implementation steps:
- Write a buildImageUrl() function that takes a base Contentstack asset URL and returns a transformed URL with width, quality, and format parameters.
- Write a buildSrcSet() function that generates a srcset string for widths [320, 640, 960, 1280].
- Create an HTML <img> element that uses the srcset, includes sizes for a two-column grid layout, sets explicit width and height, and uses loading="lazy" for below-fold images.
- Add a <link rel="preload"> tag for the first product card's image (above the fold).
- Verify that adding ?auto=webp&quality=75 to a sample image URL reduces its file size compared to the original (use browser DevTools Network tab to compare).