diff --git a/app/(home)/page.tsx b/app/(home)/page.tsx
index 2ab3c79a07..64c0f1a8ee 100644
--- a/app/(home)/page.tsx
+++ b/app/(home)/page.tsx
@@ -1,5 +1,20 @@
+import { cookies, headers } from "next/headers";
import { Home } from "@/components/home";
+import {
+ HERO_SLOGAN_VARIANT_HEADER,
+ HERO_SLOGAN_VARIANT_KEY,
+ getHeroSloganVariantFromCookieValue,
+} from "@/lib/hero-slogan-variant";
-export default function HomePage() {
- return ;
+export default async function HomePage() {
+ const [cookieStore, headerStore] = await Promise.all([
+ cookies(),
+ headers(),
+ ]);
+ const heroSloganVariant = getHeroSloganVariantFromCookieValue(
+ headerStore.get(HERO_SLOGAN_VARIANT_HEADER) ??
+ cookieStore.get(HERO_SLOGAN_VARIANT_KEY)?.value,
+ );
+
+ return ;
}
diff --git a/components/home/Hero.tsx b/components/home/Hero.tsx
index 224ab578bd..b3c82a5257 100644
--- a/components/home/Hero.tsx
+++ b/components/home/Hero.tsx
@@ -1,60 +1,24 @@
import { Button } from "@/components/ui/button";
import { CornerBox } from "@/components/ui/corner-box";
-import { Heading } from "@/components/ui/heading";
import { Text } from "@/components/ui/text";
-import { TextHighlight } from "@/components/ui";
import { HomeSection } from "@/components/home/HomeSection";
import { EnterpriseLogoGrid } from "@/components/shared/EnterpriseLogoGrid";
-import { cn } from "@/lib/utils";
import { HeroStatsStrip } from "@/components/home/HeroStatsStrip";
+import { HeroSlogan } from "@/components/home/HeroSlogan";
+import type { HeroSloganVariant } from "@/lib/hero-slogan-variant";
-export function Hero() {
+export function Hero({
+ heroSloganVariant,
+}: {
+ heroSloganVariant: HeroSloganVariant;
+}) {
return (
-
-
- Open Source
-
-
-
- AI
-
-
- Engineering
-
-
-
- Platform
-
-
-
+
Trace and evaluate AI Agents. Collaborate with your team to
diff --git a/components/home/HeroSlogan.tsx b/components/home/HeroSlogan.tsx
new file mode 100644
index 0000000000..f0e7459df6
--- /dev/null
+++ b/components/home/HeroSlogan.tsx
@@ -0,0 +1,167 @@
+"use client";
+
+import { useEffect, useRef } from "react";
+import { usePostHog } from "posthog-js/react";
+import { Heading } from "@/components/ui/heading";
+import { TextHighlight } from "@/components/ui";
+import { cn } from "@/lib/utils";
+import { usePostHogClientCapture } from "@/src/usePostHogClientCapture";
+import {
+ HERO_SLOGAN_VARIANT_KEY,
+ type HeroSloganVariant,
+} from "@/lib/hero-slogan-variant";
+
+function readStoredVariant(): HeroSloganVariant | null {
+ try {
+ const stored = localStorage.getItem(HERO_SLOGAN_VARIANT_KEY);
+ if (stored === "ai-engineering" || stored === "agent-evals") {
+ return stored;
+ }
+ } catch {
+ // localStorage unavailable (e.g. private browsing restrictions)
+ }
+ return null;
+}
+
+function persistVariant(variant: HeroSloganVariant) {
+ try {
+ localStorage.setItem(HERO_SLOGAN_VARIANT_KEY, variant);
+ } catch {
+ // ignore write failures
+ }
+}
+
+const headingClassName = cn(
+ "flex-col items-center gap-0.5 sm:gap-1 md:gap-1.5 text-center font-medium leading-[105%] max-md:max-w-[500px]",
+ "[leading-trim:both] [text-edge:cap]",
+);
+
+const desktopWordSpacing = "max-[499px]:pr-1.75 min-[500px]:pr-2";
+
+function AiEngineeringSlogan() {
+ return (
+ <>
+
+ Open Source
+
+
+
+ AI
+
+
+ Engineering
+
+
+
+ Platform
+
+ >
+ );
+}
+
+function AgentEvalsSlogan() {
+ return (
+ <>
+
+ Open Source
+
+
+
+ Agent
+
+
+ Evals
+
+
+ and
+
+
+ Tracing
+
+
+ >
+ );
+}
+
+function trackHeroSloganExposure(
+ posthog: ReturnType,
+ capture: ReturnType,
+ variant: HeroSloganVariant,
+ isNewAssignment: boolean,
+) {
+ posthog.register({ hero_slogan_variant: variant });
+ capture("hero_slogan_exposure", {
+ variant,
+ is_new_assignment: isNewAssignment,
+ });
+}
+
+export function HeroSlogan({
+ initialVariant,
+}: {
+ initialVariant: HeroSloganVariant;
+}) {
+ const posthog = usePostHog();
+ const capture = usePostHogClientCapture();
+ const trackedRef = useRef(false);
+
+ useEffect(() => {
+ const hadLocalStorage = readStoredVariant() !== null;
+ persistVariant(initialVariant);
+
+ if (trackedRef.current) {
+ return;
+ }
+
+ const runTracking = () => {
+ if (trackedRef.current) {
+ return;
+ }
+ trackedRef.current = true;
+ trackHeroSloganExposure(
+ posthog,
+ capture,
+ initialVariant,
+ !hadLocalStorage,
+ );
+ };
+
+ if ((posthog as { __loaded?: boolean }).__loaded) {
+ runTracking();
+ return;
+ }
+
+ posthog.onSessionId(runTracking);
+ }, [capture, initialVariant, posthog]);
+
+ return (
+
+ {initialVariant === "ai-engineering" ? (
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/components/home/index.tsx b/components/home/index.tsx
index 19572ac1cd..2c0750d410 100644
--- a/components/home/index.tsx
+++ b/components/home/index.tsx
@@ -9,11 +9,16 @@ import { Enterprise } from "./Enterprise";
import { WhyLangfuse } from "./WhyLangfuse";
import { GetStartedSection } from "./GetStartedSection";
import { FAQ } from "./FAQ";
+import type { HeroSloganVariant } from "@/lib/hero-slogan-variant";
-export const Home = () => (
+export const Home = ({
+ heroSloganVariant,
+}: {
+ heroSloganVariant: HeroSloganVariant;
+}) => (
<>
-
+
diff --git a/lib/hero-slogan-variant.ts b/lib/hero-slogan-variant.ts
new file mode 100644
index 0000000000..36859c1c4d
--- /dev/null
+++ b/lib/hero-slogan-variant.ts
@@ -0,0 +1,22 @@
+export const HERO_SLOGAN_VARIANT_HEADER = "x-hero-slogan-variant";
+
+export const HERO_SLOGAN_VARIANT_KEY = "langfuse-hero-slogan-variant";
+
+export type HeroSloganVariant = "ai-engineering" | "agent-evals";
+
+export function isHeroSloganVariant(value: string): value is HeroSloganVariant {
+ return value === "ai-engineering" || value === "agent-evals";
+}
+
+export function pickHeroSloganVariant(): HeroSloganVariant {
+ return Math.random() < 0.5 ? "ai-engineering" : "agent-evals";
+}
+
+export function getHeroSloganVariantFromCookieValue(
+ value: string | undefined,
+): HeroSloganVariant {
+ if (value && isHeroSloganVariant(value)) {
+ return value;
+ }
+ return pickHeroSloganVariant();
+}
diff --git a/middleware.ts b/middleware.ts
new file mode 100644
index 0000000000..7e82141b6c
--- /dev/null
+++ b/middleware.ts
@@ -0,0 +1,38 @@
+import { NextResponse } from "next/server";
+import type { NextRequest } from "next/server";
+import {
+ HERO_SLOGAN_VARIANT_KEY,
+ isHeroSloganVariant,
+ pickHeroSloganVariant,
+} from "@/lib/hero-slogan-variant";
+
+const HERO_SLOGAN_VARIANT_HEADER = "x-hero-slogan-variant";
+
+export function middleware(request: NextRequest) {
+ const existing = request.cookies.get(HERO_SLOGAN_VARIANT_KEY)?.value;
+ const variant =
+ existing && isHeroSloganVariant(existing)
+ ? existing
+ : pickHeroSloganVariant();
+
+ const requestHeaders = new Headers(request.headers);
+ requestHeaders.set(HERO_SLOGAN_VARIANT_HEADER, variant);
+
+ const response = NextResponse.next({
+ request: { headers: requestHeaders },
+ });
+
+ if (!existing || !isHeroSloganVariant(existing)) {
+ response.cookies.set(HERO_SLOGAN_VARIANT_KEY, variant, {
+ maxAge: 60 * 60 * 24 * 365,
+ path: "/",
+ sameSite: "lax",
+ });
+ }
+
+ return response;
+}
+
+export const config = {
+ matcher: "/",
+};
diff --git a/src/usePostHogClientCapture.ts b/src/usePostHogClientCapture.ts
index ae19e493f8..f91b8134cf 100644
--- a/src/usePostHogClientCapture.ts
+++ b/src/usePostHogClientCapture.ts
@@ -5,6 +5,10 @@ import { usePostHog } from "posthog-js/react";
// This preserves existing PostHog event structure while adding type safety
interface EventDefinitions {
copy_page: { type: "copy" | "chatgpt" | "claude" | "mcp" };
+ hero_slogan_exposure: {
+ variant: "ai-engineering" | "agent-evals";
+ is_new_assignment: boolean;
+ };
}
type EventName = keyof EventDefinitions;