From e5546d08601c2beb600a89383144de5507888b80 Mon Sep 17 00:00:00 2001 From: Michael Canova Date: Mon, 9 Feb 2026 14:06:51 -0500 Subject: [PATCH 1/3] [Clarity] Integrating Clarity for testing on staging --- app/layout.tsx | 2 ++ components/Clarity.tsx | 27 +++++++++++++++++++++++++++ package-lock.json | 6 ++++++ package.json | 1 + services/analytics.service.ts | 5 +++++ 5 files changed, 41 insertions(+) create mode 100644 components/Clarity.tsx diff --git a/app/layout.tsx b/app/layout.tsx index 3838fe634..37a45a6a6 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -8,6 +8,7 @@ import { SITE_CONFIG } from '@/lib/metadata'; import { GoogleAnalytics } from '@next/third-parties/google'; import { Analytics } from '@vercel/analytics/react'; import Hotjar from '@/components/Hotjar'; +import Clarity from '@/components/Clarity'; import { ClientProviders } from '@/components/providers/ClientProviders'; const geistSans = localFont({ @@ -103,6 +104,7 @@ export default async function RootLayout({ {process.env.GA_MEASUREMENT_ID && } + ); diff --git a/components/Clarity.tsx b/components/Clarity.tsx new file mode 100644 index 000000000..d0d1585f5 --- /dev/null +++ b/components/Clarity.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { useEffect } from 'react'; +import ClaritySDK from '@microsoft/clarity'; + +let isInitialized = false; + +/** + * Microsoft Clarity analytics component for session recordings, heatmaps, and user behavior. + * Only loads in production when NEXT_PUBLIC_CLARITY_ID is configured. + */ +const Clarity = () => { + const clarityId = process.env.NEXT_PUBLIC_CLARITY_ID; + const isProduction = process.env.NODE_ENV === 'production'; + + useEffect(() => { + //if (!isInitialized && isProduction && clarityId) { + if (!isInitialized && clarityId) { + ClaritySDK.init(clarityId); + isInitialized = true; + } + }, [clarityId, isProduction]); + + return null; +}; + +export default Clarity; diff --git a/package-lock.json b/package-lock.json index b636a9b1a..a4f63b285 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@headlessui/react": "^2.2.0", "@hocuspocus/provider": "^2.14.0", "@hookform/resolvers": "^4.1.0", + "@microsoft/clarity": "^1.0.2", "@next/third-parties": "^15.5.9", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-popover": "^1.1.2", @@ -3106,6 +3107,11 @@ "node": ">=10" } }, + "node_modules/@microsoft/clarity": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@microsoft/clarity/-/clarity-1.0.2.tgz", + "integrity": "sha512-9EZYROFpJxEGmQpHvUFqvD3ZJ7QQSqnibYSWmS+1xusoZfG1QQ1/Al9yVBBc11DWMbJrs1pe1hLT273it/skJg==" + }, "node_modules/@napi-rs/canvas": { "version": "0.1.88", "license": "MIT", diff --git a/package.json b/package.json index 04500781a..f62838120 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@headlessui/react": "^2.2.0", "@hocuspocus/provider": "^2.14.0", "@hookform/resolvers": "^4.1.0", + "@microsoft/clarity": "^1.0.2", "@next/third-parties": "^15.5.9", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-popover": "^1.1.2", diff --git a/services/analytics.service.ts b/services/analytics.service.ts index ebc0527e7..bac88d279 100644 --- a/services/analytics.service.ts +++ b/services/analytics.service.ts @@ -1,6 +1,7 @@ import { User } from '@/types/user'; import * as amplitude from '@amplitude/analytics-browser'; import { sendGAEvent } from '@next/third-parties/google'; +import ClaritySDK from '@microsoft/clarity'; export const LogEvent = { SIGNUP_PROMO_MODAL_OPENED: 'signup_promo_modal_opened', @@ -103,6 +104,10 @@ class AnalyticsService { identify.set(key, value); }); amplitude.identify(identify); + + if (userProperties.user_id) { + ClaritySDK.identify(userProperties.user_id); + } } static async logEvent( From b826d73d01544db9271b83dc9767995205d41dd3 Mon Sep 17 00:00:00 2001 From: Michael Canova Date: Mon, 9 Feb 2026 14:30:49 -0500 Subject: [PATCH 2/3] [Clarity] Setting it to production only after testing --- components/Clarity.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/Clarity.tsx b/components/Clarity.tsx index d0d1585f5..e3b8e64de 100644 --- a/components/Clarity.tsx +++ b/components/Clarity.tsx @@ -14,8 +14,7 @@ const Clarity = () => { const isProduction = process.env.NODE_ENV === 'production'; useEffect(() => { - //if (!isInitialized && isProduction && clarityId) { - if (!isInitialized && clarityId) { + if (!isInitialized && isProduction && clarityId) { ClaritySDK.init(clarityId); isInitialized = true; } From fe24dde96fa9d61e030b52cfeb940dec4e8adc56 Mon Sep 17 00:00:00 2001 From: Michael Canova Date: Tue, 10 Feb 2026 18:22:30 -0500 Subject: [PATCH 3/3] [Clarity] Feedback Updates --- components/Clarity.tsx | 15 +++++++-------- services/analytics.service.ts | 5 +++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/Clarity.tsx b/components/Clarity.tsx index e3b8e64de..e1ded1c2d 100644 --- a/components/Clarity.tsx +++ b/components/Clarity.tsx @@ -1,24 +1,23 @@ 'use client'; -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import ClaritySDK from '@microsoft/clarity'; -let isInitialized = false; +const clarityId = process.env.NEXT_PUBLIC_CLARITY_ID; +const isProduction = process.env.NODE_ENV === 'production'; /** * Microsoft Clarity analytics component for session recordings, heatmaps, and user behavior. - * Only loads in production when NEXT_PUBLIC_CLARITY_ID is configured. */ const Clarity = () => { - const clarityId = process.env.NEXT_PUBLIC_CLARITY_ID; - const isProduction = process.env.NODE_ENV === 'production'; + const isInitialized = useRef(false); useEffect(() => { - if (!isInitialized && isProduction && clarityId) { + if (!isInitialized.current && isProduction && clarityId) { ClaritySDK.init(clarityId); - isInitialized = true; + isInitialized.current = true; } - }, [clarityId, isProduction]); + }, []); return null; }; diff --git a/services/analytics.service.ts b/services/analytics.service.ts index bac88d279..4878926f2 100644 --- a/services/analytics.service.ts +++ b/services/analytics.service.ts @@ -105,8 +105,9 @@ class AnalyticsService { }); amplitude.identify(identify); - if (userProperties.user_id) { - ClaritySDK.identify(userProperties.user_id); + const clarityUserId = userProperties.user_id || this.userId; + if (clarityUserId) { + ClaritySDK.identify(clarityUserId); } }