Personalizing Sanity content without blowing up GROQ/CDN caching
We run a marketplace on Sanity and lean heavily on the CDN for GROQ query performance. Nearly every content request is a cache hit today and our page latency budget depends on that.
My worry with adding personalization: if queries start carrying per-user context, every request becomes a cache miss and we pay origin latency on every page view. That would be a regression we cant accept.
How does the Croct integration deal with this? Does user context end up in the GROQ queries, or does variant resolution happen somewhere else entirely?
2 answers
User context never enters your GROQ queries. The overlay model keeps the two concerns separate by design:
- Sanity keeps serving your default content exactly as today. Queries stay user-agnostic, so they remain fully cacheable by Sanity's CDN.
- Croct resolves which variant applies to each visitor on its own side. Your frontend asks Croct for the content of a slot, and the audience evaluation happens per visitor in Croct's infrastructure, not in your content queries.
In other words, personalization is resolved per slot per visitor, while your Sanity data layer stays shared and cacheable. If no experience matches a visitor, the slot falls back to the regular Sanity content.
On the latency of the Croct call itself: end-to-end response times are under 90 milliseconds at P95, and the SDKs let you define fallback content so a slow or failed fetch degrades to your default content. See the content fetching documentation for the fallback options per SDK.
Running this combination in production on a content site, can confirm the cache behavior in practice. Our GROQ hit rate did not move after rollout because the queries are byte-identical for every visitor, all the per-visitor variation comes through the slot fetch.
One implementation tip: resolve the slot content in parallel with your Sanity fetch rather than sequentially, so the personalization call does not add to the critical path. With both running concurrently the slower of the two determines latency, and in our metrics that is usually still the Sanity round trip on cache misses.
The parallel fetch tip is exactly what I needed, thanks. Prototyped it yesterday and the p95 impact on our side is within noise.