Asset
Asset
Asset reads one published asset by its UID. Use it when you know which file you need, for example the hero image an entry links to, and want its URL, file details, or extra metadata. To list assets instead, use the Asset Collection class.
stack.asset() takes one optional argument:
| Name | Type | Description |
|---|---|---|
| uid | string | UID of the asset to fetch. |
Pass the UID to stack.asset() to get an Asset. Call stack.asset() without a UID to get an AssetQuery instead.
| Name | Type | Description |
|---|---|---|
| assetUid | string | UID of the asset |
assetFields
assetFields adds optional field groups, such as visual markups or user-defined fields, to the asset in the response.
| Name | Type | Description |
|---|---|---|
| fields | string[] | Field group names, one per argument. |
Returns: Asset. The same asset, for chaining.
Validation
- There is no client-side validation. assetFields stores any string, including an empty string or a name the API does not recognize, as given.
- Passing one array, for example assetFields(['user_defined_fields']), is a compile error, because fields is a rest parameter of strings. Spread an array instead: assetFields(...groups).
- Errors surface on the fetch() call that follows, not on assetFields(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. assetFields sets the asset_fields[] query parameter to the list of names and makes no request. fetch sends the list on that call.
- The Content Delivery API accepts two group names, visual_markups and user_defined_fields. The SDK does not check the names, so it also forwards any other name.
- The API returns the groups only for assets managed in New Assets. An asset stored directly in the stack comes back without the visual_markups and user_defined_fields keys.
- The groups come in addition to the standard asset fields, such as url, filename, and content_type. They do not replace or remove any field.
- Calling assetFields again with names replaces the earlier list. Calling it with no names leaves the earlier list in place, and no method clears it.
- The groups are not part of the BaseAsset type, and their shape depends on your stack. Declare them on your own interface, and check each value before you use it.
Note The SDK's code comments also name embedded_metadata and ai_generated_metadata. The API rejects both with status 422 and error_code 141, so the request throws an APIError.
Example
Basic usage: request user-defined fields
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
interface AssetWithFields extends BaseAsset {
user_defined_fields?: Record<string, unknown>;
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack
.asset('<ASSET_UID>')
.assetFields('user_defined_fields')
.fetch<AssetWithFields>();
console.log(asset.title, asset.user_defined_fields);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}All parameters: request both field groups
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
interface AssetWithAllGroups extends BaseAsset {
user_defined_fields?: Record<string, unknown>;
visual_markups?: unknown[];
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack
.asset('<ASSET_UID>')
.assetFields('user_defined_fields', 'visual_markups')
.fetch<AssetWithAllGroups>();
console.log(asset.user_defined_fields, asset.visual_markups);
} catch (error: any) {
console.error(error);
}Edge case: pass group names from an array
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
const groups: string[] = ['user_defined_fields', 'visual_markups'];
try {
// Spread the array. Passing groups directly is a compile error.
const asset = await stack.asset('<ASSET_UID>').assetFields(...groups).fetch<BaseAsset>();
console.log(asset.uid);
} catch (error: any) {
console.error(error);
}fetch
fetch retrieves one published asset by its UID.
Returns: Promise<T>. The requested asset.
Validation
- fetch checks nothing itself. The SDK places the UID into the request path as given.
- stack.asset('') never reaches this method. The empty string returns an AssetQuery, which has no fetch, so the call throws TypeError. See the Warning on the Asset class page.
- fetch throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message. A UID that names no asset published to the environment is one cause. The API answers it with status 404, error_code 145, and the message Asset was not found.
- A network failure also throws an APIError, with status set to 0 and error_code set to the Node error code, for example ENOTFOUND.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Calls GET /assets/{asset_uid} and makes one HTTP request per call, plus any automatic retries.
- Returns the contents of the asset key on success, not the response envelope around it. When a successful response has no asset key, fetch returns the whole response body.
- Sends the environment from the stack config and every value that locale, version, includeFallback, includeDimension, includeMetadata, includeBranch, relativeUrls, and assetFields recorded on the instance. Calling fetch twice on one instance repeats the same request.
- The type argument T is a compile-time type only. The SDK does not check the response against it.
- Without a type argument, T is unknown, and TypeScript rejects property access such as result.url.
- Pass BaseAsset, which the package exports, or your own interface that extends it.
Limitations
- Does not return several assets. Use the find method of the Asset Collection class instead.
- Does not resize or crop images. Use the ImageTransform class with the returned url instead.
Example
Basic usage: fetch one asset by UID
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').fetch<BaseAsset>();
console.log(asset.uid, asset.filename, asset.url);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}All setters: shape the response before fetching
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
interface DetailedAsset extends BaseAsset {
dimension?: { height: number; width: number };
_metadata?: unknown;
_branch?: string;
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack
.asset('<ASSET_UID>')
.locale('en-us')
.includeFallback()
.version(1)
.includeDimension()
.includeMetadata()
.includeBranch()
.relativeUrls()
.assetFields('user_defined_fields')
.fetch<DetailedAsset>();
console.log(asset.url, asset._version, asset._branch, asset.dimension);
} catch (error: any) {
console.error(error);
}Error handling: read the status of a failed fetch
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
// This UID names no asset, so the API rejects the request.
const asset = await stack.asset('blt0000000000000000').fetch<BaseAsset>();
console.log(asset.url);
} catch (error: any) {
if (error.status === 0) {
console.error('Network failure:', error.error_code);
} else {
console.error('API rejected the request:', error.status, error.error_code, error.error_message);
}
}Edge case: guard a UID that comes from a variable
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
// A UID read at runtime, for example from a route parameter, can be empty.
const assetUid: string = '<ASSET_UID>';
// An empty string would return an AssetQuery, which has no fetch.
if (!assetUid) {
console.error('No asset UID set. Skipping the fetch.');
} else {
try {
const asset = await stack.asset(assetUid).fetch<BaseAsset>();
console.log(asset.url);
} catch (error: any) {
console.error(error);
}
}includeBranch
includeBranch adds the _branch field to the response, naming the branch the asset belongs to.
Returns: Asset. The same asset, for chaining.
Validation
- There is nothing to validate. includeBranch takes no arguments and cannot fail.
- Errors surface on the fetch() call that follows, not on includeBranch(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. includeBranch sets include_branch to the string 'true' and makes no request. fetch sends the flag on that call.
- _branch is not part of the BaseAsset type. Declare it on your own interface to read it without a compile error.
Limitations
- Does not choose a branch. Set branch in the stack config instead, as the Contentstack class page describes. The SDK sends that value as a request header, and without one the API reads the main branch.
Example
Basic usage: confirm which branch served the asset
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
interface BranchedAsset extends BaseAsset {
_branch?: string;
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').includeBranch().fetch<BranchedAsset>();
console.log(asset.title, 'branch:', asset._branch);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}includeDimension
includeDimension adds the image height and width to the response, as a dimension object.
Returns: Asset. The same asset, for chaining.
Validation
- There is nothing to validate. includeDimension takes no arguments and cannot fail.
- Errors surface on the fetch() call that follows, not on includeDimension(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. includeDimension sets include_dimension to the string 'true' and makes no request. fetch sends the flag on that call.
- The API returns dimension with height and width in pixels for image assets in JPG, GIF, PNG, WebP, BMP, TIFF, SVG, and PSD format. Read dimension as optional, because the API does not promise it for other files.
- Without includeDimension, the response has no dimension key.
- dimension is not part of the BaseAsset type. Declare it on your own interface to read it without a compile error.
Example
Basic usage: read an image's width and height
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
interface ImageAsset extends BaseAsset {
dimension?: { height: number; width: number };
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const image = await stack.asset('<ASSET_UID>').includeDimension().fetch<ImageAsset>();
console.log('size:', image.dimension?.width, 'x', image.dimension?.height);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Edge case: handle a file that is not an image
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
interface ImageAsset extends BaseAsset {
dimension?: { height: number; width: number };
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').includeDimension().fetch<ImageAsset>();
// content_type holds the file's MIME type, for example image/png.
if (asset.dimension) {
console.log(`${asset.filename} is ${asset.dimension.width}x${asset.dimension.height}`);
} else {
console.log(`${asset.filename} (${asset.content_type}) has no dimensions`);
}
} catch (error: any) {
console.error(error);
}includeFallback
includeFallback returns the asset from an earlier locale in the hierarchy when the requested locale has no published version of it.
Returns: Asset. The same asset, for chaining.
Validation
- There is nothing to validate. includeFallback takes no arguments and cannot fail.
- Errors surface on the fetch() call that follows, not on includeFallback(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. includeFallback sets include_fallback to the string 'true' and makes no request. fetch sends the flag on that call.
- The flag changes nothing when you request the master locale. Chain the locale method, or set locale in the stack config, to request another locale.
- The API resolves the fallback, not the SDK. It returns the asset from the nearest earlier locale in the hierarchy that has a published version.
- The response carries no separate fallback flag. Read publish_details.locale on the result to see the locale the API served, and compare it with your requested locale.
Example
Basic usage: accept an earlier locale when the French version is missing
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').locale('fr-fr').includeFallback().fetch<BaseAsset>();
console.log(asset.title, asset.url);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Edge case: detect a fallback
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
const requested = 'fr-fr';
try {
const asset = await stack.asset('<ASSET_UID>').locale(requested).includeFallback().fetch<BaseAsset>();
// publish_details.locale names the locale of the version the API served.
const served = asset.publish_details?.locale;
if (served && served !== requested) {
console.log(`No ${requested} version, served ${served} instead`);
}
} catch (error: any) {
console.error(error);
}includeMetadata
includeMetadata adds the asset's _metadata object to the response.
Returns: Asset. The same asset, for chaining.
Validation
- There is nothing to validate. includeMetadata takes no arguments and cannot fail.
- Errors surface on the fetch() call that follows, not on includeMetadata(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. includeMetadata sets include_metadata to the string 'true' and makes no request. fetch sends the flag on that call.
- _metadata is not part of the BaseAsset type. Declare it on your own interface to read it without a compile error.
- includeMetadata and the assetFields method write separate request parameters. Setting one does not set the other.
Example
Basic usage: read an asset's metadata
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
interface AssetWithMetadata extends BaseAsset {
_metadata?: unknown;
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').includeMetadata().fetch<AssetWithMetadata>();
console.log(asset.title, asset._metadata);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}locale
locale sets the locale the API returns the asset in.
| Name | Type | Description |
|---|---|---|
| locale (required) | string | Locale code to request, for example fr-fr. |
Returns: Asset. The same asset, for chaining.
Validation
- There is no client-side validation. locale accepts an empty string or a code that names no locale and stores it as given.
- Omitting the argument is a compile error, because locale declares a required string parameter.
- Errors surface on the fetch() call that follows, not on locale(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
- A code that names no locale of the stack fails with status 422 and error_code 141. The message reads Language was not found. Please try again. An empty string sends locale= and returns the master locale.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. locale sets the locale query parameter and makes no request. fetch sends the value on that call.
- The SDK sets no default on the asset. Without locale, fetch sends the locale from the stack config, if you set one there.
- With no locale at either level, fetch sends no locale parameter, and the API returns the stack's master locale.
- A value from locale replaces the stack-level locale for this request only.
- Calling locale twice replaces the first value. The SDK stores it under a single key.
- When the requested locale has no published version of the asset, fetch fails with status 404 and error_code 145. Chain the includeFallback method to receive the version from an earlier locale in the hierarchy.
Example
Basic usage: fetch an asset in French
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').locale('fr-fr').fetch<BaseAsset>();
console.log(asset.title, asset.publish_details?.locale);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Edge case: override the stack-level locale for one asset
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
// Every request from this stack sends locale=en-us unless a call sets its own.
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
locale: 'en-us',
});
try {
// This request sends locale=fr-fr instead of en-us.
const asset = await stack
.asset('<ASSET_UID>')
.locale('fr-fr')
.includeFallback()
.fetch<BaseAsset>();
console.log(asset.publish_details?.locale);
} catch (error: any) {
console.error(error);
}relativeUrls
relativeUrls adds the relative_urls flag to the asset request.
Returns: Asset. The same asset, for chaining.
Validation
- There is nothing to validate. relativeUrls takes no arguments and cannot fail.
- Errors surface on the fetch() call that follows, not on relativeUrls(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. relativeUrls sets relative_urls to the string 'true' and makes no request. fetch sends the flag on that call.
- The API ignores the flag. The asset's url comes back as a full URL with the asset domain, the same as without relativeUrls.
- To serve the asset through your own domain or proxy, read the path from url with the URL class. Then prefix the path with your host, as the second example shows.
Example
Basic usage: send the flag and read the asset URL
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').relativeUrls().fetch<BaseAsset>();
// The url still includes the asset domain.
console.log('url:', asset.url);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Edge case: serve the asset through your own host
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
// The host that proxies your asset requests.
const assetHost = 'https://assets.example.com';
try {
const asset = await stack.asset('<ASSET_UID>').fetch<BaseAsset>();
// Keep only the path of the asset URL, then put your host in front of it.
const path = new URL(asset.url).pathname;
const fullUrl = new URL(path, assetHost).toString();
console.log(fullUrl);
} catch (error: any) {
console.error(error);
}version
version adds a version number to the asset request.
| Name | Type | Description |
|---|---|---|
| version (required) | number | Version number of the asset to fetch. |
Returns: Asset. The same asset, for chaining.
Validation
- There is no client-side validation. version converts the number to a string and stores it as given.
- 0, a negative number, a decimal, and NaN all go out unchanged, for example as version=NaN.
- Passing a string, for example version('2'), is a compile error, because the parameter type is number.
- Errors surface on the fetch() call that follows, not on version(). fetch() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. version sets the version query parameter to String(version) and makes no request. fetch sends the value on that call.
- The SDK sets no default. Without version, fetch sends no version parameter, and the API returns the published version of the asset.
- The API returns the published version of the asset whatever value you pass. It ignores version on a request that carries an environment, and the SDK always sends the environment from the stack config. A version that does not exist returns the published version, not an error. For the rule, refer to Get a single asset in the Content Delivery API reference.
- Calling version twice replaces the first value. The SDK stores it under a single key.
- Read _version on the result to confirm the version the API returned.
Example
Basic usage: fetch version 1 of an asset
import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const asset = await stack.asset('<ASSET_UID>').version(1).fetch<BaseAsset>();
console.log(asset.filename, 'version', asset._version);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}