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:

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. 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

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()

createCachelyContentfulClient from @cachely-io/sdk/contentful also 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)
  }
})
Need help understanding this?Ask Cachely Copilot about features, setup, or integrations.
Ask Copilot →