Ga4: Install, Source and Security | FunnelSlayer

Ga4

Published by danzam98 in claude-skills-toolkit

Review recommended15 installs

What this skill does

>-

Add Ga4 to your agent

Review the source and files first. When you are ready, copy the prompt instruction or use the CLI command supported by your environment.

Install with a prompt

Paste this into a compatible coding agent:

add this skill "ga4" from https://github.com/danzam98/claude-skills-toolkit

Install with the CLI

Run this command in a controlled environment after reviewing the repository:

npx skills add https://github.com/danzam98/claude-skills-toolkit --skill ga4

Skill instructions

GA4 + GTM for Next.js SaaS

Stack: Next.js 16 App Router + @next/third-parties + Supabase Auth + GA4 + GTM (all free)

Table of Contents


Quick Start

// app/layout.tsx
import { GoogleTagManager } from '@next/third-parties/google'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <GoogleTagManager gtmId="GTM-XXXXXXX" />
      </body>
    </html>
  )
}

Then in GTM: Create GA4 Configuration tag with G-XXXXXXXXXX Measurement ID, trigger "All Pages".

Why GTM with GA4

GTM is a centralized hub for all tracking. Benefits:

Without GTMWith GTM
Hardcoded analytics callsConfigure in web interface
Redeploy to change trackingUpdate without code deploys
Testing in productionPreview mode before publish
Scattered event codeUnified dataLayer pattern

GTM "listens" to dataLayer and routes events to GA4. Your Next.js code stays clean.

Workflow

  • 1. Create GTM container → note GTM-XXXXXXX
  • 2. Add <GoogleTagManager> to root layout
  • 3. Create GA4 Config tag in GTM (Measurement ID + All Pages trigger)
  • 4. Publish GTM, verify in GA4 Realtime
  • 5. Add funnel events (scroll, CTA, sign_up, feature_use)
  • 6. Register custom parameters in GA4 Admin > Custom Definitions
  • 7. Mark sign_up as conversion in GA4 Admin > Events
  • 8. Configure User-ID for cross-session tracking (optional)
  • 9. Build funnel exploration in GA4 Explore

Funnel Events

StepEventParametersHow
1. Landingpage_view(automatic)GA4 Config tag
2. Scrollscroll_depthscroll_percentGTM Scroll trigger (25/50/75/90%)
3. Section Viewsection_viewsection_nameGTM Element Visibility trigger
4. CTA Clickcta_clickcta_text, cta_positionGTM Click trigger or dataLayer
5. Sign-upsign_upmethod, user_iddataLayer on Supabase auth
6. Feature Usefeature_usefeature_namedataLayer on action

Note: GA4 Enhanced Measurement auto-tracks scroll at 90% only. Use GTM for granular 25/50/75/90%.

dataLayer Push Pattern

// Declare type for TypeScript
declare global {
  interface Window { dataLayer: Record<string, any>[]; }
}

// Generic push helper
function trackEvent(event: string, params: Record<string, any>) {
  window.dataLayer?.push({ event, ...params });
}

// Examples
trackEvent('cta_click', { cta_text: 'Get Started', cta_position: 'hero' });
trackEvent('feature_use', { feature_name: 'export_report' });

GTM Tag Configurations

Scroll Depth (25/50/75/90%)

  1. Variables > Built-in: Enable Scroll Depth Threshold, Scroll Depth Units, Scroll Direction
  2. Trigger > Scroll Depth: Vertical, Percentages: 25,50,75,90
  3. Tag > GA4 Event: scroll_depth, param scroll_percent = {{Scroll Depth Threshold}}

Section Visibility

Track which landing page sections users actually see (not just scroll past):

// Add to section elements
<section className="ga-section-tracking" data-section-name="features">
  {/* content */}
</section>
  1. Variable > Auto-Event Variable: Element Attribute data-section-name
  2. Trigger > Element Visibility: CSS .ga-section-tracking, 50% visible, once per element
  3. Tag > GA4 Event: section_view, param section_name = {{AEV - section-name}}

CTA Click (Two Methods)

Method A: No-Code (GTM only)

<button class="cta-signup" data-cta_text="Sign Up" data-cta_position="hero">
  Create Account
</button>
  • Variable > DOM Element: CSS .cta-signup, attribute data-cta_text
  • Trigger > Click - All Elements: Click Classes contains cta-signup

Method B: dataLayer (more reliable for dynamic content)

<button onClick={() => trackEvent('cta_click', { cta_text: 'Sign Up', cta_position: 'hero' })}>
  Create Account
</button>
  • Trigger > Custom Event: cta_click

Sign-up Conversion Tracking

Since you use Supabase + Google OAuth, fire sign_up after auth confirms:

// In your auth provider or layout
useEffect(() => {
  const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
    if (event === 'SIGNED_IN' && session?.user) {
      window.dataLayer?.push({
        event: 'sign_up',          // GA4 recommended event name
        method: 'google',          // Auth method
        user_id: session.user.id   // For User-ID tracking
      });
    }
  });
  return () => subscription.unsubscribe();
}, []);

Alternative: Trigger on redirect page (e.g., /dashboard or /auth/callback) if that's where new users land.

Critical: Mark sign_up as conversion in GA4 Admin > Events > Toggle "Mark as conversion".

In-App Feature Usage

Track what paid users do after sign-up:

// Strategy: Single event + feature_name parameter (scales better than separate events)
function useFeature(featureName: string) {
  trackEvent('feature_use', {
    feature_name: featureName,
    feature_category: 'reports' // optional grouping
  });
}

// Usage
useFeature('generate_report');
useFeature('export_csv');
useFeature('invite_team_member');

Why single event? GA4 limits unique event names (~500). Using feature_use with a feature_name dimension scales indefinitely.

A/B Testing (No Google Optimize)

Google Optimize sunset Sept 2023. DIY approach with cookies:

// middleware.ts - Assign variant server-side (prevents flicker)
import { NextResponse } from 'next/server'

export function middleware(request) {
  const response = NextResponse.next()
  if (!request.cookies.get('exp_hero_cta')) {
    const variant = Math.random() < 0.5 ? 'A' : 'B'
    response.cookies.set('exp_hero_cta', variant, { maxAge: 60 * 60 * 24 * 30 })
  }
  return response
}
// Track with variant in all relevant events
const variant = cookies().get('exp_hero_cta')?.value || 'A'

trackEvent('cta_click', {
  cta_text: variant === 'A' ? 'Start Trial' : 'Get Started',
  experiment_variant: variant
});

Analyze: GA4 Explore > Create segments for experiment_variant = A vs B, compare conversion rates.

Validation

StepToolWhat to Check
1GTM PreviewTags fire at correct moments, parameters populated
2GA4 DebugViewEvents arrive with all params, correct names
3GA4 RealtimeLive traffic appears within 30s
4GA4 ReportsData in standard reports (24-48h delay)

Critical checks:

  • sign_up fires exactly once per conversion
  • Scroll events fire at correct thresholds
  • CTA clicks register with correct cta_text/cta_position

References

TopicReference
Event schemas & namingEVENTS.md
Complete GTM configsGTM-TAGS.md
Funnel analysis in GA4FUNNEL-ANALYSIS.md
DIY A/B testingAB-TESTING.md
TroubleshootingDEBUGGING.md

Key Gotchas

  • Cookie consent: GTM tags won't fire until consent given (GDPR)
  • Custom params: Register in GA4 Admin > Custom Definitions before they appear in reports
  • Recommended events: Use GA4's exact names (sign_up, login, purchase) for default reports
  • User-ID: Requires explicit setup in GA4 Config tag for cross-session tracking
  • Event limits: Max ~500 unique event names per property - consolidate with parameters
  • Data delay: Real reports take 24-48h; use Realtime/DebugView for testing

Files included

  • references/AB-TESTING.md
  • references/DEBUGGING.md
  • references/EVENTS.md
  • references/FUNNEL-ANALYSIS.md
  • references/GTM-TAGS.md
  • SKILL.md