Contentful Integration

CMS Assets has first-class support for Contentful. It handles both image and video asset URLs and provides a response transformer that rewrites Contentful CDN URLs in your API responses.


Supported URL patterns

Contentful serves assets from two CDN domains. CMS Assets handles both:

Images:

https://images.ctfassets.net/{spaceId}/path/to/image.jpg

Videos:

https://videos.ctfassets.net/{spaceId}/path/to/video.mp4

Both are rewritten to:

https://your-tenant.cmsassets.com/path/to/asset

Tenant setup

When creating your tenant, select Contentful as the CMS type and provide your space ID:

FieldValue
CMSContentful
Space IDyour-space-id
Website domainyour-site.com

Two origins are automatically configured:

  • Image origin: https://images.ctfassets.net/{spaceId}
  • Video origin: https://videos.ctfassets.net/{spaceId}

You don't need to set these manually. CMS Assets resolves them from your space ID.


Video support

Contentful serves video and image assets from separate CDN domains. CMS Assets handles both automatically:

  • Image requests (jpeg, jpg, png, webp, avif, svg, pdf) route to images.ctfassets.net
  • Video requests (mp4, webm, mov, m4v) route to videos.ctfassets.net

Range requests for video seeking and streaming are fully supported.


Response transformer

Install the response transformer to automatically rewrite Contentful asset URLs in your API responses:

npm install @synchronized-studio/response-transformer

Basic usage

import { transformContentfulAssetUrls } from "@synchronized-studio/response-transformer"

const entries = await contentfulClient.getEntries()

const transformed = transformContentfulAssetUrls(entries, {
  spaceId: "your-space-id",
  cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})

What gets transformed

The transformer processes the entire JSON response and rewrites all matching URLs. This includes:

  • Asset fields
  • Rich text embedded assets
  • Image fields
  • Video fields
  • Linked entries with media references

Any URL matching images.ctfassets.net/{spaceId} or videos.ctfassets.net/{spaceId} is rewritten to your CMS Assets proxy URL. Query parameters (like Contentful's image transformations) are stripped during rewriting.

Using an environment variable

Set CMS_ASSETS_URL in your environment and omit the cmsAssetsUrl option:

CMS_ASSETS_URL=https://your-tenant.cmsassets.com
const transformed = transformContentfulAssetUrls(entries, {
  spaceId: "your-space-id"
})

Nuxt / SSR integration

For Nuxt or other SSR frameworks, wrap your Contentful client or API layer:

// composables/useContentfulData.ts
import { transformContentfulAssetUrls } from "@synchronized-studio/response-transformer"

export async function useContentfulData() {
  const entries = await contentfulClient.getEntries()

  return transformContentfulAssetUrls(entries, {
    spaceId: "your-space-id",
    cmsAssetsUrl: useRuntimeConfig().public.cmsAssetsUrl
  })
}

Using the generic transformer

You can also use the unified transformCmsAssetUrls function:

import { transformCmsAssetUrls } from "@synchronized-studio/response-transformer"

const transformed = transformCmsAssetUrls(entries, {
  cms: "contentful",
  spaceId: "your-space-id",
  cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})

Contentful Image API

Contentful's Image API adds query parameters like ?w=800&h=600&fit=fill for on-the-fly image transformations. When assets are proxied through CMS Assets:

  • The edge cache strips query parameters from the cache key for image types
  • This means all image transformation variants share the same cache entry
  • If you rely on Contentful's Image API transformations, the first cached version will be served for all variants

If you need different image sizes, apply transformations on the client side or serve each size from a different path.


Advanced options

Custom transformers

Add additional transformers that run after the default Contentful ones:

const transformed = transformContentfulAssetUrls(entries, {
  spaceId: "your-space-id",
  transformers: [
    (jsonStr, { base }) => {
      return jsonStr.replaceAll("old-pattern", "new-pattern")
    }
  ]
})

Post-transform hook

Run a function on the parsed result after all URL replacements:

const transformed = transformContentfulAssetUrls(entries, {
  spaceId: "your-space-id",
  postTransform: (data) => {
    return data
  }
})

Error handling

By default, transform errors are logged as warnings and the original data is returned unchanged. You can provide a custom error handler:

const transformed = transformContentfulAssetUrls(entries, {
  spaceId: "your-space-id",
  onError: (error) => {
    Sentry.captureException(error)
  }
})
Need help understanding this?Ask CMS Assets Copilot about features, setup, or integrations.
Ask Copilot →