Contentful Integration
Cachely 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. Cachely 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.cachely.io/path/to/asset
Tenant setup
When creating your tenant, select Contentful as the CMS type and provide your space ID:
| Field | Value |
|---|---|
| CMS | Contentful |
| Space ID | your-space-id |
| Website domain | your-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. Cachely resolves them from your space ID.
Video support
Contentful serves video and image assets from separate CDN domains. Cachely 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.
Cachely SDK
Install the Cachely SDK to route Contentful API and asset requests through your edge domain:
npm install @cachely-io/sdk
Recommended: the Cachely adapter
Keep your normal contentful.createClient and plug in the Cachely adapter. This is exactly what npx @cachely-io/sdk setup wires into an existing Contentful project, and it only routes through Cachely when CACHELY_PROXY_URL is set (otherwise the client talks to Contentful directly):
import { createClient } from 'contentful'
import { createContentfulCachelyAdapter } from '@cachely-io/sdk/contentful'
const cachelyProxyUrl = process.env.CACHELY_PROXY_URL
export const client = createClient({
space: 'your-space-id',
accessToken: process.env.CONTENTFUL_TOKEN!,
...(cachelyProxyUrl
? { adapter: createContentfulCachelyAdapter({ proxyUrl: cachelyProxyUrl, spaceId: 'your-space-id' }) }
: {}),
})
const entries = await client.getEntries()
createCachelyContentfulClientfrom@cachely-io/sdk/contentfulalso exists, but it targets the chainable v10+ client API. For most projects the adapter above is the recommended path.
Preview / bypass
Pass a wrapFetch that appends ?preview=1 so the edge skips its cache for fresh editor/preview content:
adapter: createContentfulCachelyAdapter({
proxyUrl: cachelyProxyUrl,
spaceId: 'your-space-id',
wrapFetch: (f) => (input, init) => {
const url = new URL(typeof input === 'string' ? input : (input as Request).url)
url.searchParams.set('preview', '1')
return f(url.toString(), init)
},
})
AI transforms
Apply a named AI Transform profile to eligible responses with the adapter's transform option:
adapter: createContentfulCachelyAdapter({
proxyUrl: cachelyProxyUrl,
spaceId: 'your-space-id',
transform: 'czech',
})
What gets rewritten
The adapter rewrites both API URLs (cdn.contentful.com, preview.contentful.com) and asset URLs (images.ctfassets.net, videos.ctfassets.net, assets.ctfassets.net, downloads.ctfassets.net) to your project's edge domain. Image API query parameters (?w=800&h=600&fit=fill) are preserved end-to-end.
Rewriting URLs without intercepting fetch (asset-only)
If you only need asset URL rewriting — no API proxy, e.g. when you already have a response in hand — use createCachelyUrlRewriter instead. (contentful is a built-in provider id, so you can pass it directly.)
import { createCachelyUrlRewriter } from '@cachely-io/sdk'
const rewrite = createCachelyUrlRewriter({
tenant: 'your-tenant',
provider: 'contentful',
providerConfig: { spaceId: 'your-space-id' },
})
const { url } = rewrite('https://images.ctfassets.net/your-space-id/assetId/token/img.jpg?w=800')
// → https://your-tenant.cachely.io/assetId/token/img.jpg?w=800
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 Cachely:
- 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)
}
})