Integrate Microsoft Clarity with Your Next.js App
chamupathi mendis

chamupathi mendis @chamupathi_mendis_cdd19da

About: Over 7 years of industry experience. Talks about implementing features using the best practices.

Joined:
Jan 5, 2025

Integrate Microsoft Clarity with Your Next.js App

Publish Date: Mar 23
3 0

Why Track User Behavior?

Understanding how users interact with your website is crucial for improving the user experience. Behavior analytics tools help identify friction points, optimize conversions, and provide insights into how users navigate your application.

Why Microsoft Clarity?

Microsoft Clarity is a free behavior analytics tool that offers:
✅ Heatmaps – Visualize where users click and scroll.
✅ Session Recordings – Replay user sessions to understand their journey.
✅ Insights – Identify pain points and engagement metrics.
✅ Google Analytics Integration – Combine behavioral data with standard analytics.

In this guide, we’ll integrate Microsoft Clarity into a Next.js app and ensure it runs efficiently without affecting server-side rendering (SSR). Let’s get started!


Video of Clarity dashboard


1. Create a next app

If you don’t have an existing Next.js project, create one using:

npx create-next-app ms-clarity-example

Enter fullscreen mode Exit fullscreen mode

2. Install Microsoft Clarity

Install the Clarity package using:

npm install @microsoft/clarity
Enter fullscreen mode Exit fullscreen mode

3. Get Your Clarity Project ID

2.1. Create a project via
https://clarity.microsoft.com/

2.2. Navigate to Settings → Overview and copy the Project ID.


4. Initializing Clarity in Next.js

To start tracking user sessions, we need to initialize Clarity using:

Clarity.init(<project-id>);
Enter fullscreen mode Exit fullscreen mode

🚨 The Catch: Run Clarity on the Client Side Only

  • Clarity should not run on the server side, as it relies on window.
  • We must use useEffect to ensure it runs only in the browser.
  • The best place to initialize Clarity is in the top-level layout.tsx file.

❌ Initial Approach: Adding it Directly in RootLayout.tsx

"use client"

/* Rest of the code */
export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {

    useEffect(() => {
        if (typeof window !== "undefined") {
            Clarity.init(process.env.NEXT_PUBLIC_CLARITY_ID!);
        }
      }, []);

/* Rest of the code */
Enter fullscreen mode Exit fullscreen mode

⚠️ Problem: RootLayout Becomes a Client Component

By adding "use client", we force RootLayout to be client-rendered, preventing Next.js from utilizing SSR and static generation. Instead, we should move Clarity initialization to a separate component.


Hook vs a component

Hook

If the logic is moved to a hook we have the same problem RootLayout needs to be a client component.

import Clarity from "@microsoft/clarity";
import { useEffect } from "react";

export default function useMsClarity() {
    useEffect(() => {
        if (typeof window !== "undefined") {
            Clarity.init(process.env.NEXT_PUBLIC_CLARITY_ID!);
        }
      }, []);
}

// Rootlayout.tsx
"use client"
export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {

    // use hook
      useMsClarity();

Enter fullscreen mode Exit fullscreen mode

Component

Lets create a client component to hold the logic

"use client";
import Clarity from "@microsoft/clarity";
import { useEffect } from "react";

export default function useMsClarity() {
    useEffect(() => {
        if (typeof window !== "undefined") {
            Clarity.init(<project-id>);
        }
      }, []);

    return null;
}
Enter fullscreen mode Exit fullscreen mode

Use the component in root layout.

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import BaseLayout from "./ui/layouts/BaseLayout";
import ClarityInit from "./ui/analytics/clarity-init";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
    title: "MS clarity test",
    description: "MS clarity test",
};

export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {

    return (
        <html lang="en">
            <body className={inter.className}>
                <ClarityInit />
                <BaseLayout>
                    {children}
                </BaseLayout>
            </body>
        </html>
    );
}
Enter fullscreen mode Exit fullscreen mode

By moving the logic to a separate component (ClarityInit), we avoid making RootLayout a client component, allowing the rest of the app to benefit from Server-Side Rendering (SSR).


6. Store the Clarity Project ID Securely

finally move the clarity-project-id to an env variable to make sure that it doe not pushed to version control system.

Clarity.init(process.env.NEXT_PUBLIC_CLARITY_ID!);
Enter fullscreen mode Exit fullscreen mode

Note
The NEXT_PUBLIC_ prefix is needed so that nextjs can read the env variable.

add it to .env file as well

NEXT_PUBLIC_CLARITY_ID=<clarity-project-id>

Enter fullscreen mode Exit fullscreen mode

Ms-clarity will start to collect sessions and you can see them in the dashboard.

git hub link with code example.
https://github.com/chamupathi/ms-clarity

Comments 0 total

    Add comment