Prismic Integration
CMS Assets has first-class support for Prismic. It handles both Prismic CDN URL patterns and provides a response transformer that rewrites asset URLs in your Prismic API responses.
Supported URL patterns
Prismic serves images and video from two different CDN domains. CMS Assets handles both:
Images (with optional Image CDN query params):
https://images.prismic.io/your-repo/path/to/image.png?auto=format,compress&w=1024&fm=webp&q=80
Video:
https://your-repo.cdn.prismic.io/your-repo/path/to/video.mp4
Both are rewritten to your tenant URL (query params on images are preserved):
https://your-tenant.cmsassets.com/your-repo/path/to/image.png?auto=format,compress&w=1024&fm=webp&q=80
https://your-tenant.cmsassets.com/your-repo/path/to/video.mp4
Tenant setup
When creating your tenant, select Prismic as the CMS type and provide your repository name:
| Field | Value |
|---|---|
| CMS | Prismic |
| Repository name | your-repo |
| Website domain | your-site.com |
Two origins are used: https://your-repo.cdn.prismic.io (video and some assets) and https://images.prismic.io/your-repo (images with Image CDN). CMS Assets routes requests to the correct origin based on the URL pattern.
Note: The website domain is important for Prismic. It's sent as the
Refererheader when fetching from origin, which preventsAccessDeniederrors from Prismic's S3-backed storage.
Response transformer
Install the response transformer to automatically rewrite Prismic asset URLs in your API responses:
npm install @synchronized-studio/response-transformer
Basic usage
import { transformPrismicAssetUrls } from "@synchronized-studio/response-transformer"
const data = await prismicClient.getAllByType("page")
const transformed = transformPrismicAssetUrls(data, {
repository: "your-repo",
cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})
What gets transformed
The transformer processes the entire JSON response and rewrites all matching URLs. This includes:
- Document fields
- Rich text content
- Image fields
- Media links
- Slices and nested structures
Any URL matching your-repo.cdn.prismic.io or images.prismic.io/your-repo is rewritten to your CMS Assets proxy URL.
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 = transformPrismicAssetUrls(data, {
repository: "your-repo"
})
Nuxt / SSR integration
For Nuxt or other SSR frameworks, wrap your Prismic client or API layer:
// composables/usePrismicData.ts
import { transformPrismicAssetUrls } from "@synchronized-studio/response-transformer"
export async function usePrismicData(type: string) {
const data = await prismicClient.getAllByType(type)
return transformPrismicAssetUrls(data, {
repository: "your-repo",
cmsAssetsUrl: useRuntimeConfig().public.cmsAssetsUrl
})
}
Query params
Prismic often appends query parameters like ?auto=format&w=800 to image URLs. The transformer strips these during URL rewriting since the edge cache ignores query parameters for image types. This prevents duplicate cache entries and ensures consistent caching.
Preview & fresh-fetch bypass
By default, API proxy responses are cached at the edge (typically 60 seconds). For preview mode or fresh-fetch use cases — where you need guaranteed-fresh data from Prismic — you can bypass the cache per request.
The edge proxy already supports this: any API request with ?preview=1 skips cache entirely and fetches directly from upstream. The withCacheBypass wrapper makes it easy to apply this from your app code.
Setup
Create a small wrapper around createCmsAssetsFetch:
// utils/withCacheBypass.ts
export function withCacheBypass(
baseFetch: typeof fetch,
bypass: boolean | (() => boolean),
param = 'preview',
): typeof fetch {
return function bypassFetch(input, init) {
const active = typeof bypass === 'function' ? bypass() : bypass
if (!active) return baseFetch(input, init)
const url = typeof input === 'string'
? input
: input instanceof URL ? input.href : input.url
if (!url) return baseFetch(input, init)
const parsed = new URL(url)
if (!parsed.searchParams.has(param)) {
parsed.searchParams.set(param, '1')
}
if (input instanceof Request) {
return baseFetch(new Request(parsed.toString(), input), init)
}
return baseFetch(parsed.toString(), init)
}
}
Nuxt integration example
// plugins/prismic.ts
import * as prismic from '@prismicio/client'
import { createCmsAssetsFetch } from '@synchronized-studio/cmsassets-core'
import { withCacheBypass } from '~/utils/withCacheBypass'
export default defineNuxtPlugin(() => {
const { enabled: isPreview } = usePreviewMode()
const baseFetch = createCmsAssetsFetch({
tenant: 'my-site',
provider: 'prismic',
})
// When preview mode is active, all API requests bypass edge cache
const cmsFetch = withCacheBypass(baseFetch, () => isPreview.value)
const client = prismic.createClient('my-repo', {
fetch: cmsFetch,
})
return { provide: { prismic: { client } } }
})
How it works
- Normal requests go through the proxy and are served from edge cache when available (
X-Cache: HITorMISS) - Preview/fresh requests have
?preview=1appended automatically, which tells the proxy to skip cache and fetch directly from Prismic (X-Cache: BYPASS) - The bypass signal is evaluated per request, so switching preview mode on/off takes effect immediately
Static bypass
If you need a client that always bypasses cache (e.g., for a dedicated preview endpoint), pass true instead of a function:
const previewFetch = withCacheBypass(baseFetch, true)
const previewClient = prismic.createClient('my-repo', { fetch: previewFetch })
What this does not do
- Does not bypass asset proxy caching. The
?preview=1param only affects/~apiroutes. Asset URLs are unaffected — this is intentional, since preview use cases are about fresh API data, not fresh images. - Does not change how Prismic preview refs work. Prismic's own preview mechanism uses a
refparameter to point to a draft release. That ref flows through the proxy as a normal query parameter.withCacheBypassensures the proxy doesn't serve a stale cached version of the previous ref.
Advanced options
Custom transformers
You can add additional transformers that run after the default Prismic ones:
const transformed = transformPrismicAssetUrls(data, {
repository: "your-repo",
transformers: [
(jsonStr, { base }) => {
// Custom string replacement on the serialized JSON
return jsonStr.replaceAll("old-pattern", "new-pattern")
}
]
})
Post-transform hook
Run a function on the parsed result after all URL replacements:
const transformed = transformPrismicAssetUrls(data, {
repository: "your-repo",
postTransform: (data) => {
// Modify the final parsed object
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 = transformPrismicAssetUrls(data, {
repository: "your-repo",
onError: (error) => {
Sentry.captureException(error)
}
})