Skip to main content

Implementation with Next.js

This guide demonstrates how to preload the Kameleoon Web Experimentation technology with anti-flicker and execute the script engine.js after React hydration to ensure a seamless user experience.


Overview

  1. Preload Kameleoon: Download the engine in advance so it’s cached by the time we run it.
  2. Anti-Flicker CSS: Hide content until the engine is ready, avoiding visible layout shifts.
  3. Post-Hydration Execution: Insert the engine script after React hydrates, eliminating hydration errors.

Client Configuration

Before adding the code, adjust these Kameleoon settings:


Components

note

The domain for your Kameleoon scripts may vary from one project to another. Depending on their creation date, your projects may be hosted on either kameleoon.eu or kameleoon.io. Ensure you use the domain displayed in your project in the Kameleoon App.

Create two components and insert them at the application level, ensuring they’re the very first tags inside <head> and <body>.

1. KameleoonHead

Add this component to <head> in app/layout.tsx (or app/_document.tsx).

import Script from "next/script";

const ANTIFLICKER_CSS = `* { visibility: hidden !important; background-image: none !important; }`;

const ANTIFLICKER_JS = `
var kameleoonLoadingTimeout = 1000;
window.kameleoonQueue = window.kameleoonQueue || [];
window.kameleoonStartLoadTime = new Date().getTime();

window.kameleoonDisplayPage = function (fromEngine) {
if (!fromEngine) {
window.kameleoonTimeout = true;
}

var sheet = document.getElementById("kameleoonLoadingStyleSheet");
if (sheet && sheet.parentNode) {
sheet.parentNode.removeChild(sheet);
}
};

window.kameleoonDisplayPageTimeOut = window.setTimeout(
window.kameleoonDisplayPage,
kameleoonLoadingTimeout
);
`;

export function KameleoonHead() {
return (
<>
{/* Preload Kameleoon engine for instant cached execution */}
<link
rel="preload"
hhref="https://SITECODE.kameleoon.io/engine.js"
as="script"
fetchPriority="high"
/>

{/* Anti-flicker style to prevent hydration issues */}
<style id="kameleoonLoadingStyleSheet">{ANTIFLICKER_CSS}</style>

{/* Anti-flicker logic */}
<Script
id="kameleoon-antiflicker"
strategy="beforeInteractive"
dangerouslySetInnerHTML={{ __html: ANTIFLICKER_JS }}
/>
</>
);
}

Note: The default anti-flicker timeout is 1000 ms. Adjust kameleoonLoadingTimeout as needed.


2. KameleoonScript

Place this component inside <body>. It loads the engine after hydration and handles route changes manually.

"use client";

import { usePathname, useSearchParams } from "next/navigation";
import { useCallback, useEffect, useRef } from "react";

export function KameleoonScript() {
const pathname = usePathname();
const searchParams = useSearchParams();
const isFirstRender = useRef(true);

const loadEngine = useCallback(() => {
if (document.getElementById("kameleoon-engine")) return;

const script = document.createElement("script");
script.src = "https://SITECODE.kameleoon.io/engine.js";
script.async = true;
script.id = "kameleoon-engine";
document.head.appendChild(script);
}, []);

// Execute Kameleoon after hydration
useEffect(() => {
loadEngine();
}, [loadEngine]);

// Manual SPA control for route changes
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
window.Kameleoon?.Analyst?.load();
}, [pathname, searchParams]);

return null;
}

Usage in RootLayout

Example layout combining both components:

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<KameleoonHead />
<link
rel="preload"
as="image"
href="https://images.unsplash.com/photo-1551434678-e076c223a692?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80"
fetchPriority="high"
/>
</head>
<body>
{/* Client component signals hydration and runs Kameleoon */}
<KameleoonScript />
<div className="min-h-screen bg-background">
<Navigation />
<main className="container mx-auto px-4 py-8">{children}</main>
</div>
</body>
</html>
);
}

Key Takeaways

  • Preload Early: Ensures the engine is cached for near-instant execution.
  • Hide Then Reveal: Anti-flicker CSS prevents visible page flashes.
  • Manual Route Handling: Disabling SPA mode and calling Analyst.load() on route changes gives precise control.

With these steps, your Next.js application will load Kameleoon efficiently and without hydration issues.