Storyblok webhooks purge our CDN cache, where does personalized content fit?
Today an editor publishes in Storyblok -> webhook fires -> we purge the CDN cache for the affected paths -> next request rebuilds the page. Works well for the static parts of the site.
Now we are adding Croct experiences on a few blocks and I am trying to place personalized routes in this picture. My mental model has a hole: if a page can render differently per visitor, does it belong in the CDN cache at all? And when an editor publishes a block that is also mapped to a slot, does my purge webhook even matter for the experience content, or is that served from somewhere else entirely?
How do others split cached defaults from per-user variants
2 answers
The split is cleaner than you might expect, and it confirms the way you are already thinking about it.
The rule: keep cached pages user-agnostic. The Storyblok default is what belongs in the CDN, because it is the same bytes for everyone. Per-visitor variants are resolved by Croct per request, so they should never be written into a shared cache in the first place. Any route that renders personalized content leaves your cache layer and renders dynamically.
If your frontend is Next.js this actually happens on its own: fetchContent reads the request, which opts the route into dynamic rendering. So personalized routes exit the static cache path automatically, and your webhook purge keeps governing only the static rest of the site.
Your second question is the key architectural point. The two content paths are separate. When an editor publishes a Storyblok block, that updates the fallback, the default that non-matched visitors see, and your purge webhook handles it exactly as today. Experience and variant content is managed and served by Croct separately, resolved per request, so it is never sitting stale in your CDN and needs no purging from your side.
So: nothing to add to the webhook, just make sure personalized routes are not accidentally behind a shared cache with long TTLs.
Clear. So the mental model is two planes: fallback plane owned by Storyblok plus my purge pipeline, variant plane owned by Croct per request. That closes the hole, thanks.
One practical addition: audit your CDN config for personalized paths after the rollout. We had a default cache rule on /* that quietly applied to a newly personalized route until we added an exclusion. Nothing broke because the route rendered dynamically at origin, but the CDN was caching the first response for a few minutes. An explicit no-store rule per personalized path makes the split visible in the config instead of implicit.