Skip to main content
Server-side rendering introduces a timing challenge: the server has to resolve parameters during the request lifecycle so the first paint is correct, but the client also needs the assignments for interactive behaviour. If you fetch the bundle twice — once on the server, once on the client — hydration can re-resolve to different values and cause a visible swap. The pattern is always the same:
  1. Fetch the bundle once on the server.
  2. Pass it to the client via your framework’s data-loading mechanism.
  3. Initialize the client SDK with the server-provided bundle as localConfig.
  4. The client uses the same bundle and resolves identically — no second fetch on hydration.

SvelteKit

Layout load (server)

loadTrafficalBundle respects standard HTTP caching, so subsequent SSR requests within the cache TTL benefit from SvelteKit’s fetch cache.

Root layout (server + client)

On the Svelte SDK the server-fetched bundle goes through initialBundle (not localConfig). initialBundle is what marks the provider ready during SSR and lets it resolve on the server so the first paint is correct. localConfig is the separate build-time/offline fallback bundle.

Page

The server resolves with data.traffical.bundle and renders the correct variant. The client picks up the same bundle and resolves identically. No swap.

Next.js (App Router / RSC)

The React SDK has no @traffical/react/server entry point. Fetch the config bundle directly from the SDK config endpoint — the same URL the client SDK calls — and pass it as localConfig:
Wrapping the fetch in Next.js’s fetch integration (next: { revalidate }) caches it, so subsequent renders within the cache window don’t re-fetch.

Next.js (Pages Router)

Why this works

  • Same bundle, same hash, same answer. Both server and client read the same bundle and run the same SHA-256 v2 bucketing. The same userId always resolves to the same allocation.
  • One network fetch. The server fetches; the client receives the bundle inline. No second fetch on hydration.
  • First paint is correct. Because the server resolves before rendering, the user sees the right variant immediately. No flash of original content.

Pitfalls

  • Mismatched user IDs. If the server reads userId from a session cookie but the client reads it from a different source, the two will resolve to different buckets and you’ll see a swap on hydration. Make sure both sides use the same value.
  • Use the SDK key on both sides. The same traffical_sk_... SDK key (scopes sdk:read+sdk:write) is browser-safe and is used both client-side in the TrafficalProvider and server-side when you fetch the bundle (the plain fetch on Next.js, loadTrafficalBundle on SvelteKit). There is no separate server secret for the SDK path — keep management-scoped keys out of all rendering code.
  • Stale bundle on long-lived pages. The client refreshes the bundle every 60s by default. SPAs running for hours will pick up new policies automatically. For static pages, a hard reload is enough.

Next steps

SSR + hydration pattern

Full end-to-end example.

React SDK

Provider, hooks, options.

Svelte SDK

Stores, context, runes.