Guides
Caching
Cache the manifest
GET /manifest is the reusable configuration endpoint. It does not query consent
records or depend on the visitor's location. The backend generates its revision
from the configuration and returns it as an ETag.
Add these options to the backend configuration:
These are the defaults, in seconds. The resulting header is
public, s-maxage=300, stale-while-revalidate=86400, sent as both
Cache-Control and CDN-Cache-Control. Vercel's CDN consumes the shared-cache
directives from a bare Cache-Control and strips them before forwarding; the
second header keeps them visible to app servers reading the manifest through
the CDN. A policy change alters the
revision, but a shared cache can continue serving the previous response within
its cache window. Purge the relevant cache or choose shorter durations when your
rollout requires it. A revision is an identity, not a remote cache invalidation
command.
Keep the tenant, backend URL and language query in the cache key. Preserve
Vary: Origin when CORS emits it. Do not combine manifests from different
projects just because their endpoint paths match.
Keep visitor state out of shared caches
GET /init and GET /subjects/:id return no-store.
Do not override that header with a CDN rule. /init contains a resolved policy
for request inputs; subject endpoints contain private state.
A server framework can reuse /manifest and resolve it locally for each incoming
request. That removes the backend initialization round trip on a manifest cache
hit while preserving per-request policy selection. It does not remove later
consent writes or make request cookies shareable.
The framework adapters honour both directives above in their in-process cache.
After sMaxAge seconds they keep serving the cached manifest for up to
staleWhileRevalidate seconds while one background request revalidates it with
the ETag, and a failed revalidation keeps the cached copy. A shorter
staleWhileRevalidate therefore bounds how long an app server can keep serving
an old policy after this backend becomes unreachable, at the cost of blocking
requests on the backend once that window closes.
Cache the Global Vendor List
GVL caching is separate from manifest HTTP caching. Supply a cache adapter with your server-side GVL configuration. Concurrent misses share an in-flight fetch, but persistent reuse requires the configured cache.
A device can narrow the list per request with x-c15t-vendors. That header is
not part of the cache key. The backend caches one document per endpoint,
language, and configured gvl.vendorIds, then narrows that document for each
request. What a client sends therefore cannot create cache entries, and cannot
add an upstream fetch. /init answers with Cache-Control: no-store and lists
the header in Vary regardless, because the vendors it names are
request-specific.
The backend loads a GVL only for a matched IAB rule. The GVL TTL uses
milliseconds, unlike manifestCache.
| Adapter | Use it when |
|---|---|
createMemoryCacheAdapter() | One long-lived process can keep its own cache. Memory is not shared between instances. |
createUpstashRedisAdapter({ url, token }) | Serverless or multiple instances need a shared cache. Install the optional @upstash/redis peer. |
createUpstashRedisAdapterFromClient(client) | Your application already owns an Upstash client. |
createCloudflareKVAdapter(namespace) | A compatible runtime supplies a KV namespace. This does not supply a database driver. |
Custom CacheAdapter implementations provide get, set, delete and has.
set receives its optional TTL in milliseconds. Cache operations should fit the
request latency budget. A failed GVL fetch returns no usable list; verify that
behavior with your IAB client rather than assuming a warm cache on every request.
Choose the adapter path in data fetching or Next.js rendering and deployment.