DEV Community

pipipi-dev
pipipi-dev

Posted on

Visualizing User Behavior: Setting Up GA4 and Microsoft Clarity

This article is Day 21 of the Solo SaaS Development Advent Calendar 2025.

Yesterday I wrote about implementing tiered pricing with Stripe. Today, I'll cover setting up Google Analytics 4 and Microsoft Clarity to visualize user behavior.

πŸ€” Why Analytics Matter

Once you launch a service, you naturally want to know how it's being used:

  • Which pages are most viewed?
  • Where do users drop off?
  • Which buttons get clicked?

Without this data, you can't make informed decisions about improvements. Instead of relying on gut feelings, I wanted to make data-driven decisions. That's why I implemented analytics tools.

Tool Selection

I use three tools in combination:

Tool Purpose Features
Google Analytics 4 Traffic analysis User count, page views, traffic sources
Microsoft Clarity Behavior visualization Heatmaps, session recordings
Search Console SEO analysis Search keywords, rankings

All three are free. While GA4 alone provides basic analysis, combining it with Clarity reveals the "why" behind the numbers.

πŸ“ˆ Setting Up Google Analytics 4

Component Implementation

In Next.js, we use next/script to load the GA4 script:

// components/analytics/GoogleAnalytics.tsx
'use client';

import Script from 'next/script';

interface GoogleAnalyticsProps {
  measurementId: string;
}

export function GoogleAnalytics({ measurementId }: GoogleAnalyticsProps) {
  if (!measurementId) {
    return null;
  }

  return (
    <>
      <Script
        src={`https://www.googletagmanager.com/gtag/js?id=${measurementId}`}
        strategy="afterInteractive"
      />
      <Script id="google-analytics" strategy="afterInteractive">
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${measurementId}', {
            page_path: window.location.pathname,
          });
        `}
      </Script>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

By specifying strategy="afterInteractive", the script runs without blocking page load, preserving user experience while tracking.

Adding to Layout

Load the component in your root layout. Check for the environment variable to ensure it only runs in production:

// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  const gaMeasurementId = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID;

  return (
    <html>
      <body>
        {children}
        {gaMeasurementId && <GoogleAnalytics measurementId={gaMeasurementId} />}
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

Sending Custom Events

For tracking specific actions like button clicks, use custom events:

export function trackEvent(
  eventName: string,
  eventParams?: Record<string, string | number | boolean>
) {
  if (typeof window !== 'undefined' && 'gtag' in window) {
    (window as Window & { gtag: (...args: unknown[]) => void }).gtag(
      'event',
      eventName,
      eventParams
    );
  }
}

// Usage examples
trackEvent('button_click', { button_name: 'signup' });
trackEvent('content_view', { content_id: '123' });
Enter fullscreen mode Exit fullscreen mode

πŸŽ₯ Setting Up Microsoft Clarity

Clarity visualizes user behavior through heatmaps and session recordings. While GA4 tells you "what happened," Clarity shows you "why it happened."

Component Implementation

Similar to GA4, load it using next/script:

// components/analytics/MicrosoftClarity.tsx
'use client';

import Script from 'next/script';

interface MicrosoftClarityProps {
  projectId: string;
}

export function MicrosoftClarity({ projectId }: MicrosoftClarityProps) {
  if (!projectId) {
    return null;
  }

  return (
    <Script id="microsoft-clarity" strategy="afterInteractive">
      {`
        (function(c,l,a,r,i,t,y){
          c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
          t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
          y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
        })(window, document, "clarity", "script", "${projectId}");
      `}
    </Script>
  );
}
Enter fullscreen mode Exit fullscreen mode

User Identification

To identify logged-in users, use Clarity's API:

export function identifyClarityUser(userId: string) {
  if (typeof window !== 'undefined' && 'clarity' in window) {
    (window as Window & { clarity: (...args: unknown[]) => void }).clarity(
      'identify',
      userId
    );
  }
}

// Set tags for segmentation
export function setClarityTag(key: string, value: string) {
  if (typeof window !== 'undefined' && 'clarity' in window) {
    (window as Window & { clarity: (...args: unknown[]) => void }).clarity(
      'set',
      key,
      value
    );
  }
}

// Usage examples
identifyClarityUser('user_123');
setClarityTag('plan', 'premium');
Enter fullscreen mode Exit fullscreen mode

By setting tags per plan, you can analyze differences in behavior between free and paid users.

πŸ” Setting Up Search Console

Foundation for SEO Analysis

Search Console analyzes your performance in Google search:

  • What keywords are users searching for?
  • How many times did you appear in search results?
  • What's your click-through rate?

Unlike GA4 and Clarity, it shows user behavior before they reach your site.

Ownership Verification

To use Search Console, you need to verify site ownership. The HTML tag method is the simplest:

// app/layout.tsx
export const metadata: Metadata = {
  verification: {
    google: 'your-verification-code',
  },
};
Enter fullscreen mode Exit fullscreen mode

This outputs a <meta name="google-site-verification"> tag. Just click the verify button in the Search Console dashboard to complete setup.

Note that unlike GA4 and Clarity, data takes 1-2 days to appear. Make it a habit to check regularly.

πŸ”— Tool Integration

Connecting the three tools enables deeper analysis.

GA4 and Search Console Integration

Link Search Console from the GA4 admin panel to combine search queries with on-site behavior analysis.

This allows analysis like "Which pages do users who came from this search keyword view most?"

GA4 and Clarity Integration

Enable "Google Analytics integration" in Clarity settings to link GA4 sessions with Clarity recordings.

When GA4 shows a page with high bounce rate, you can watch the Clarity recordings for that page to understand why.

πŸ’‘ Implementation Tips

Enable Only in Production

Development traffic creates noise in your data. Use environment variables to enable analytics only in production:

# .env.local (development)
# Don't set these

# Vercel environment variables (production)
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
NEXT_PUBLIC_CLARITY_PROJECT_ID=xxxxxxxxxx
Enter fullscreen mode Exit fullscreen mode

If the environment variable isn't set, the component renders nothing.

Data Reflection Timing

Tool Reflection Time
GA4 Real-time
Clarity Real-time
Search Console 1-2 days

GA4 and Clarity data is immediately available, but Search Console takes time. I check SEO data the next day.

CSP Configuration

If you have Content Security Policy (CSP) configured, you need to allow the analytics domains:

// middleware.ts
const cspHeader = `
  script-src 'self' https://www.googletagmanager.com https://*.clarity.ms;
  connect-src 'self' https://www.google-analytics.com https://*.clarity.ms;
`;
Enter fullscreen mode Exit fullscreen mode

Forgetting this will block the analytics scripts.

βœ… Summary

I covered setting up three analytics tools:

Tool Purpose
GA4 Traffic analysis, detailed tracking with custom events
Clarity Visualize behavior with heatmaps and session recordings
Search Console SEO analysis with search keywords and rankings

Key implementation points: enable only in production, don't forget CSP settings, and integrate the tools together.

For solo development, you don't need to track every metric. Start with "which pages are most viewed" and "where users drop off," then add more tracking as needed.

Tomorrow I'll cover building a multi-tenant SaaS as a solo developer.


Other Articles in This Series

  • Day 20: Tiered Pricing with Stripe: Monetization for Solo Developers
  • Day 22: Building Multi-tenant SaaS as a Solo Developer

Top comments (0)