Sanity Integration

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


Supported URL patterns

Sanity serves all assets from a single CDN domain with different path prefixes for images and files.

Images:

https://cdn.sanity.io/images/{projectId}/{dataset}/{assetId}-{width}x{height}.{format}

Files (video, PDF, etc.):

https://cdn.sanity.io/files/{projectId}/{dataset}/{hash}.{extension}

Both are rewritten to:

https://your-tenant.cmsassets.com/{assetId-or-hash}.{ext}

Tenant setup

When creating your tenant, select Sanity as the CMS type and provide your project ID:

FieldValue
CMSSanity
Project IDyour-project-id
Website domainyour-site.com

Two origins are automatically configured:

  • Image origin: https://cdn.sanity.io/images/{projectId}/production
  • File origin: https://cdn.sanity.io/files/{projectId}/production

The dataset defaults to production. If your project uses a different dataset (e.g. staging), use the custom origin override instead of the Project ID field and set both origins manually.


File and video support

Sanity serves images and files from the same domain (cdn.sanity.io) using different path prefixes. CMS Assets handles both automatically:

  • Image requests (jpeg, jpg, png, webp, avif, svg) route to cdn.sanity.io/images/…
  • File requests (mp4, webm, mov, m4v, pdf) route to cdn.sanity.io/files/…

Range requests for video seeking and streaming are fully supported.


Response transformer

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

npm install @synchronized-studio/response-transformer

Basic usage

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

const data = await sanityClient.fetch('*[_type == "page"]{ ..., "imageUrl": image.asset->url }')

const transformed = transformSanityAssetUrls(data, {
  projectId: "your-project-id",
  cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})

What gets transformed

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

  • Resolved image asset URLs (cdn.sanity.io/images/…)
  • Resolved file asset URLs (cdn.sanity.io/files/…)
  • Any URL matching the project ID and dataset in the Sanity CDN pattern

Query parameters (like Sanity's image transformations ?w=800&h=600&fit=crop) are stripped during rewriting.

Non-production datasets

If your project uses a dataset other than production, pass the dataset option:

const transformed = transformSanityAssetUrls(data, {
  projectId: "your-project-id",
  dataset: "staging",
  cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})

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 = transformSanityAssetUrls(data, {
  projectId: "your-project-id"
})

Nuxt / SSR integration

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

// composables/useSanityData.ts
import { transformSanityAssetUrls } from "@synchronized-studio/response-transformer"

export async function useSanityData() {
  const data = await sanityClient.fetch('*[_type == "page"]{ ... }')

  return transformSanityAssetUrls(data, {
    projectId: "your-project-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(data, {
  cms: "sanity",
  projectId: "your-project-id",
  cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})

Sanity Image Pipeline

Sanity's image pipeline adds query parameters like ?w=800&h=600&fit=crop&auto=format 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 Sanity's image pipeline 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 Sanity ones:

const transformed = transformSanityAssetUrls(data, {
  projectId: "your-project-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 = transformSanityAssetUrls(data, {
  projectId: "your-project-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 = transformSanityAssetUrls(data, {
  projectId: "your-project-id",
  onError: (error) => {
    Sentry.captureException(error)
  }
})
Need help understanding this?Ask CMS Assets Copilot about features, setup, or integrations.
Ask Copilot →