Back to Skills
    🦞

    add-analytics

    Add Google Analytics 4 tracking to any project.

    By @jeftekhari
    View on GitHub
    SKILL.md
    ---
    name: add-analytics
    description: Add Google Analytics 4 tracking to any project. Detects framework, adds tracking code, sets up events, and configures privacy settings.
    argument-hint: "<measurement-id> [--events] [--consent] [--debug]"
    ---
    
    # Google Analytics 4 Setup Skill
    
    You are setting up Google Analytics 4 (GA4) for a project. Follow this comprehensive guide to add analytics properly.
    
    ## Arguments
    
    Parse the following from `$ARGUMENTS`:
    - **Measurement ID**: Format `G-XXXXXXXXXX` (required, ask if not provided)
    - **--events**: Include custom event tracking helpers
    - **--consent**: Include cookie consent integration
    - **--debug**: Enable debug mode for development
    
    ## Step 1: Detect Project Type
    
    Scan the project to determine the framework/setup:
    
    ```
    Priority detection order:
    1. next.config.js/ts → Next.js
    2. nuxt.config.js/ts → Nuxt.js
    3. astro.config.mjs → Astro
    4. svelte.config.js → SvelteKit
    5. remix.config.js → Remix
    6. gatsby-config.js → Gatsby
    7. vite.config.js + src/App.vue → Vue + Vite
    8. vite.config.js + src/App.tsx → React + Vite
    9. angular.json → Angular
    10. package.json with "react-scripts" → Create React App
    11. index.html only → Plain HTML
    12. _app.tsx/jsx → Next.js (App Router check: app/ directory)
    ```
    
    Also check for:
    - TypeScript usage (tsconfig.json)
    - Existing analytics (search for gtag, GA, analytics)
    - Package manager (pnpm-lock.yaml, yarn.lock, package-lock.json)
    
    ## Step 2: Validate Measurement ID
    
    The Measurement ID must:
    - Start with `G-` (GA4 format)
    - Be followed by exactly 10 alphanumeric characters
    - Example: `G-ABC1234567`
    
    If the user provides a `UA-` ID, inform them:
    > "You provided a Universal Analytics ID (UA-). GA4 uses Measurement IDs starting with 'G-'.
    > Universal Analytics was sunset in July 2024. You'll need to create a GA4 property at analytics.google.com"
    
    ## Step 3: Implementation by Framework
    
    ### Next.js (App Router - app/ directory)
    
    Create `app/layout.tsx` modification or create `components/GoogleAnalytics.tsx`:
    
    ```tsx
    // components/GoogleAnalytics.tsx
    'use client'
    
    import Script from 'next/script'
    
    interface GoogleAnalyticsProps {
      measurementId: string
    }
    
    export function GoogleAnalytics({ measurementId }: GoogleAnalyticsProps) {
      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}');
            `}
          </Script>
        </>
      )
    }
    ```
    
    Add to root layout:
    ```tsx
    // app/layout.tsx
    import { GoogleAnalytics } from '@/components/GoogleAnalytics'
    
    // Add inside <body> or <html>:
    <GoogleAnalytics measurementId="G-XXXXXXXXXX" />
    ```
    
    ### Next.js (Pages Router - pages/ directory)
    
    Modify `pages/_app.tsx`:
    
    ```tsx
    // pages/_app.tsx
    import type { AppProps } from 'next/app'
    import Script from 'next/script'
    
    const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID
    
    export default function App({ Component, pageProps }: AppProps) {
      return (
        <>
          <Script
            src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
            strategy="afterInteractive"
          />
          <Script id="google-analytics" strategy="afterInteractive">
            {`
              window.dataLayer = window.dataLayer || [];
              function gtag(){dataLayer.push(arguments);}
              gtag('js', new Date());
              gtag('config', '${GA_MEASUREMENT_ID}');
            `}
          </Script>
          <Component {...pageProps} />
        </>
      )
    }
    ```
    
    ### React (Vite/CRA)
    
    Create `src/lib/analytics.ts`:
    
    ```typescript
    // src/lib/analytics.ts
    export const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID
    
    declare global {
      interface Window {
        gtag: (...args: unknown[]) => void
        dataLayer: unknown[]
      }
    }
    
    export const initGA = () => {
      if (typeof window === 'undefined') return
    
      const script = document.createElement('script')
      script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`
      script.async = true
      document.head.appendChild(script)
    
      window.dataLayer = window.dataLayer || []
      window.gtag = function gtag() {
        window.dataLayer.push(arguments)
      }
      window.gtag('js', new Date())
      window.gtag('config', GA_MEASUREMENT_ID)
    }
    
    export const pageview = (url: string) => {
      window.gtag('config', GA_MEASUREMENT_ID, {
        page_path: url,
      })
    }
    
    export const event = (action: string, params?: Record<string, unknown>) => {
      window.gtag('event', action, params)
    }
    ```
    
    Initialize in `src/main.tsx`:
    
    ```tsx
    import { initGA } from './lib/analytics'
    
    // Initialize before render
    if (import.meta.env.PROD) {
      initGA()
    }
    ```
    
    ### Vue 3 (Vite)
    
    Create `src/plugins/analytics.ts`:
    
    ```typescript
    // src/plugins/analytics.ts
    import type { App } from 'vue'
    import type { Router } from 'vue-router'
    
    const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID
    
    declare global {
      interface Window {
        gtag: (...args: unknown[]) => void
        dataLayer: unknown[]
      }
    }
    
    export const analyticsPlugin = {
      install(app: App, { router }: { router: Router }) {
        // Load gtag script
        const script = document.createElement('script')
        script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`
        script.async = true
        document.head.appendChild(script)
    
        window.dataLayer = window.dataLayer || []
        window.gtag = function gtag() {
          window.dataLayer.push(arguments)
        }
        window.gtag('js', new Date())
        window.gtag('config', GA_MEASUREMENT_ID)
    
        // Track route changes
        router.afterEach((to) => {
          window.gtag('config', GA_MEASUREMENT_ID, {
            page_path: to.fullPath,
          })
        })
    
        // Provide global methods
        app.config.globalProperties.$gtag = window.gtag
      }
    }
    ```
    
    ### Nuxt 3
    
    Create `plugins/analytics.client.ts`:
    
    ```typescript
    // plugins/analytics.client.ts
    export default defineNuxtPlugin(() => {
      const config = useRuntimeConfig()
      const measurementId = config.public.gaMeasurementId
    
      if (!measurementId) return
    
      // Load gtag
      useHead({
        script: [
          {
            src: `https://www.googletagmanager.com/gtag/js?id=${measurementId}`,
            async: true,
          },
          {
            innerHTML: `
              window.dataLayer = window.dataLayer || [];
              function gtag(){dataLayer.push(arguments);}
              gtag('js', new Date());
              gtag('config', '${measurementId}');
            `,
          },
        ],
      })
    
      // Track route changes
      const router = useRouter()
      router.afterEach((to) => {
        window.gtag('config', measurementId, {
          page_path: to.fullPath,
        })
      })
    })
    ```
    
    Add to `nuxt.config.ts`:
    
    ```typescript
    export default defineNuxtConfig({
      runtimeConfig: {
        public: {
          gaMeasurementId: process.env.NUXT_PUBLIC_GA_MEASUREMENT_ID,
        },
      },
    })
    ```
    
    ### Astro
    
    Create `src/components/Analytics.astro`:
    
    ```astro
    ---
    // src/components/Analytics.astro
    interface Props {
      measurementId: string
    }
    
    const { measurementId } = Astro.props
    ---
    
    <script
      is:inline
      define:vars={{ measurementId }}
      src={`https://www.googletagmanager.com/gtag/js?id=${measurementId}`}
    ></script>
    
    <script is:inline define:vars={{ measurementId }}>
      window.dataLayer = window.dataLayer || [];
      function gtag() {
        dataLayer.push(arguments);
      }
      gtag('js', new Date());
      gtag('config', measurementId);
    </script>
    ```
    
    Add to layout:
    
    ```astro
    ---
    import Analytics from '../components/Analytics.astro'
    ---
    <html>
      <head>
        <Analytics measurementId="G-XXXXXXXXXX" />
      </head>
    </html>
    ```
    
    ### SvelteKit
    
    Create `src/lib/analytics.ts` and `src/routes/+layout.svelte`:
    
    ```typescript
    // src/lib/analytics.ts
    import { browser } from '$app/environment'
    
    export const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID
    
    export function initGA() {
      if (!browser) return
    
      const script = document.createElement('script')
      script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`
      script.async = true
      document.head.appendChild(script)
    
      window.dataLayer = window.dataLayer || []
      window.gtag = function gtag() {
        window.dataLayer.push(arguments)
      }
      window.gtag('js', new Date())
      window.gtag('config', GA_MEASUREMENT_ID)
    }
    
    export function trackPageview(url: string) {
      if (!browser) return
      window.gtag('config', GA_MEASUREMENT_ID, { page_path: url })
    }
    ```
    
    ```svelte
    <!-- src/routes/+layout.svelte -->
    <script lang="ts">
      import { onMount } from 'svelte'
      import { page } from '$app/stores'
      import { initGA, trackPageview } from '$lib/analytics'
    
      onMount(() => {
        initGA()
      })
    
      $: if ($page.url.pathname) {
        trackPageview($page.url.pathname)
      }
    </script>
    
    <slot />
    ```
    
    ### Plain HTML
    
    Add to `<head>`:
    
    ```html
    <!-- Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'G-XXXXXXXXXX');
    </script>
    ```
    
    ## Step 4: Environment Variables
    
    Create or update `.env` / `.env.local`:
    
    ```bash
    # For Next.js
    NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
    
    # For Vite (React/Vue/Svelte)
    VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX
    
    # For Nuxt
    NUXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
    ```
    
    Add to `.env.example` if it exists (without the actual ID):
    
    ```bash
    # Google Analytics 4 Measurement ID
    NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
    ```
    
    **IMPORTANT**: Add `.env.local` to `.gitignore` if not already present.
    
    ## Step 5: Event Tracking Helpers (if --events flag)
    
    Create a comprehensive events utility:
    
    ```typescript
    // lib/analytics-events.ts
    
    /**
     * GA4 Event Tracking Utilities
     *
     * Recommended events: https://support.google.com/analytics/answer/9267735
     */
    
    type GTagEvent = {
      action: string
      category?: string
      label?: string
      value?: num
    
    ... (truncated)