Docs

Anti-Flicker & SSR

Prevent content flashing during split test assignment

Last updated:

The SDK uses a three-tier approach to prevent content flashing when split test assignments load.

Tier 1: localStorage Cache

On repeat visits, the SDK reads cached assignments from localStorage synchronously before making any network calls. This means returning visitors see the correct variation instantly with no flicker.

Caching is on by default. You can control cache behavior with staleTTL and maxAge:

typescript
await SplitTesting.init({
  publicApiKey: 'YOUR_PUBLIC_API_KEY',
  propertyId: 'YOUR_PROPERTY_ID',
  staleTTL: 60000,     // refresh in background after 1 minute
  maxAge: 86400000,    // expire cache after 24 hours
});
  • staleTTL: After this many milliseconds, the SDK serves the cached value immediately but fetches fresh config in the background. Default is 0 (always refresh in background).
  • maxAge: After this many milliseconds, the cache is considered expired and the SDK waits for a fresh fetch before resolving. Default is 86400000 (24 hours).

To manually clear the localStorage cache (e.g., during development or after a test is reconfigured):

typescript
// Wipe cached config and assignments for this property
SplitTesting.clearCache();

Tier 2: SSR Bootstrap

Pass pre-evaluated assignments from the server to skip the network call entirely on the client. This gives you zero flicker and zero latency on first visit.

Server

typescript
// Server-side: evaluate assignments
import SplitTesting from '@sessionsight/split-testing';

await SplitTesting.init({
  publicApiKey: 'YOUR_PUBLIC_API_KEY',
  propertyId: 'YOUR_PROPERTY_ID',
});

const bootstrap = SplitTesting.getAssignments();
// Pass 'bootstrap' to the client (e.g., inject into the HTML as JSON)

Client

typescript
// Client-side: use pre-resolved assignments
await SplitTesting.init({
  publicApiKey: 'YOUR_PUBLIC_API_KEY',
  propertyId: 'YOUR_PROPERTY_ID',
  bootstrap, // from the server
});

// No network call needed. Assignments are available immediately.
const headline = SplitTesting.get('hero-headline', 'Welcome');

The SDK still fetches fresh config in the background to keep the cache warm for subsequent page loads.

Tier 3: Anti-Flicker Snippet

For cases where neither cache nor bootstrap is available (first visit, no SSR), enable the anti-flicker option to hide elements until assignments resolve.

typescript
await SplitTesting.init({
  publicApiKey: 'YOUR_PUBLIC_API_KEY',
  propertyId: 'YOUR_PROPERTY_ID',
  antiFlicker: true,
});

Then mark the elements that depend on split test values with data-ss-split:

html
<h1 data-ss-split>Welcome to Acme</h1>
<div data-ss-split id="pricing">...</div>

When antiFlicker is enabled, the SDK injects a <style> tag that sets visibility: hidden on all [data-ss-split] elements. Once assignments are resolved, the style tag is removed and elements become visible with the correct content.

Only elements with data-ss-split are hidden. The rest of your page loads normally.

Choosing a Strategy

ScenarioRecommended approach
Returning visitorsAutomatic (localStorage cache handles it)
Server-rendered pages (Next.js, SvelteKit, etc.)SSR bootstrap
Static sites, first visitAnti-flicker snippet
API-only backends, no SSRAnti-flicker snippet