Nuxt + Storyblok variants swap in after hydration, did I wire this wrong?
I have a Nuxt 3 app rendering Storyblok blocks, with Croct added as a client-side plugin:
// plugins/croct.client.tsimport croct from '@croct/plug';
export default defineNuxtPlugin(() => { croct.plug({appId: 'my-app-id'});});Expected: personalized block is rendered directly.
Actual: the default Storyblok block renders first, then the personalized variant swaps in a moment after hydration. You can clearly see teh switch on slower connections.
Is this expected behavior for a client plugin, or did I wire something wrong?
2 answers
That is expected for the way you wired it, not a bug. A .client.ts plugin only runs in the browser, so the fetch happens after the page is already rendered. Client-side fetching swaps content in after load by design, which is exactly the switch you are seeing.
What removes the flicker is server-side resolution. The Nuxt SDK supports SSR, so the slot is resolved during the server render and the personalized variant is already in the initial HTML. There is nothing left to swap on the client.
So the fix is to drop the manual client plugin and use the Nuxt SDK's server-side path instead. Your Storyblok blocks stay wired exactly as they are: the block content acts as the default fallback, so if no experience applies (or a fetch fails) the page renders the regular Storyblok content with no visual difference.
Moved the fetch to the server render and the swap is gone. Makes sense that the client plugin was the culprit, thanks.
One thing to add: even after moving to SSR, keep passing explicit fallback content on your fetches. That way the default Storyblok block still renders cleanly when no experience matches the visitor, and you never end up with an empty region while debugging. It also makes local development nicer because the page behaves the same with or without experiences running.