DEV Community

Brendan Cowley
Brendan Cowley

Posted on

Google Analytics & Sveltekit

Depending on your architecture setting up tracking can either be pretty straight forward... or "pretty straight forward". A lot of the times with SPA's it's the latter. This is the way we (DragonByte Digital Solutions) figured out how to do it after a bit of head banging. Hope this helps!

Google Analytics 4 Setup Guide for SvelteKit

This guide covers how to properly set up Google Analytics 4 (GA4) in a SvelteKit application to track all page views, including client-side navigation.

Prerequisites

  1. A Google Analytics 4 property set up
  2. Your GA4 Measurement ID (format: G-XXXXXXXXXX)
  3. A SvelteKit application

Step 1: Add GA4 Script to app.html

Add the Google Analytics script to your src/app.html file in the <head> section:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <link rel="icon" href="%sveltekit.assets%/images/favicon.png" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />

        <!-- Google tag (gtag.js) -->
        <script async src="https://www.googletagmanager.com/gtag/js?id=YOUR_MEASUREMENT_ID"></script>
        <script>
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', 'YOUR_MEASUREMENT_ID', { send_page_view: false });
        </script>

        %sveltekit.head%
    </head>
    <body data-sveltekit-preload-data="hover">
        <div style="display: contents">%sveltekit.body%</div>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Important Notes:

  • Replace YOUR_MEASUREMENT_ID with your actual GA4 Measurement ID
  • Set send_page_view: false to disable automatic page view tracking (we'll handle this manually for SPAs)

Step 2: Create the Analytics Tracking Logic

Create a new file src/lib/analytics.js:

// src/lib/analytics.js

const GA_MEASUREMENT_ID = 'YOUR_MEASUREMENT_ID'; // Replace with your actual ID

export function sendPageView(url) {
    if (typeof window !== 'undefined' && window.gtag) {
        window.gtag('event', 'page_view', {
            page_path: url,
            page_location: window.location.href,
            page_title: document.title
        });
    }
}

export function sendCustomEvent(eventName, parameters = {}) {
    if (typeof window !== 'undefined' && window.gtag) {
        window.gtag('event', eventName, parameters);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Set Up Layout-Level Tracking

Update your root layout file src/routes/+layout.svelte:

<script>
    import { onMount } from 'svelte';
    import { afterNavigate } from '$app/navigation';
    import { sendPageView } from '$lib/analytics.js';

    // Your other imports...

    onMount(() => {
        // Send initial page view
        sendPageView(window.location.pathname + window.location.search);

        // Set up navigation tracking
        afterNavigate((nav) => {
            if (nav.to?.url) {
                const newPath = nav.to.url.pathname + nav.to.url.search;
                sendPageView(newPath);
            }
        });
    });
</script>

<!-- Your layout content -->
<slot />
Enter fullscreen mode Exit fullscreen mode

Step 4: Environment Variables (Optional but Recommended)

For better security and flexibility, use environment variables:

  1. Create or update your .env file:
PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
Enter fullscreen mode Exit fullscreen mode
  1. Update src/app.html:
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', '%sveltekit.env.PUBLIC_GA_MEASUREMENT_ID%', { send_page_view: false });
</script>
Enter fullscreen mode Exit fullscreen mode
  1. Update src/lib/analytics.js:
import { PUBLIC_GA_MEASUREMENT_ID } from '$env/static/public';

const GA_MEASUREMENT_ID = PUBLIC_GA_MEASUREMENT_ID;
// ... rest of the code
Enter fullscreen mode Exit fullscreen mode

Step 5: Verify Your Setup

Test in Development

  1. Open your browser's developer tools
  2. Go to the Network tab
  3. Navigate through your site
  4. Look for requests to google-analytics.com or googletagmanager.com

Test in Production

  1. Deploy your site
  2. Go to Google Analytics → Realtime → Events
  3. Navigate through your site
  4. You should see page_view events appearing in real-time

Common Issues and Solutions

Issue: Page views not tracking

Solution: Make sure you're not blocking GA in development. Add this to your vite.config.js:

export default defineConfig({
    plugins: [sveltekit()],
    server: {
        fs: {
            allow: ['..']
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

Issue: Duplicate page views

Solution: Ensure you're only calling sendPageView once per navigation. The setup above handles this correctly.

Issue: GA not loading in development

Solution: This is normal. GA works best in production. You can add a development check:

export function sendPageView(url) {
    if (typeof window !== 'undefined' && window.gtag && import.meta.env.PROD) {
        window.gtag('event', 'page_view', {
            page_path: url,
            page_location: window.location.href,
            page_title: document.title
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Advanced Features

Custom Events

Track custom user interactions:

// In any component
import { sendCustomEvent } from '$lib/analytics.js';

function handleButtonClick() {
    sendCustomEvent('button_click', {
        button_name: 'contact_form',
        page_location: window.location.pathname
    });
}
Enter fullscreen mode Exit fullscreen mode

Enhanced Ecommerce (if applicable)

// Track purchases
gtag('event', 'purchase', {
    transaction_id: 'T_12345',
    value: 25.42,
    currency: 'USD',
    items: [
        {
            item_id: 'SKU_12345',
            item_name: 'Product Name',
            price: 25.42,
            quantity: 1
        }
    ]
});
Enter fullscreen mode Exit fullscreen mode

Complete Example Files

src/app.html

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <link rel="icon" href="%sveltekit.assets%/images/favicon.png" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />

        <!-- Google tag (gtag.js) -->
        <script async src="https://www.googletagmanager.com/gtag/js?id=%sveltekit.env.PUBLIC_GA_MEASUREMENT_ID%"></script>
        <script>
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '%sveltekit.env.PUBLIC_GA_MEASUREMENT_ID%', { send_page_view: false });
        </script>

        %sveltekit.head%
    </head>
    <body data-sveltekit-preload-data="hover">
        <div style="display: contents">%sveltekit.body%</div>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

src/lib/analytics.js

import { PUBLIC_GA_MEASUREMENT_ID } from '$env/static/public';

const GA_MEASUREMENT_ID = PUBLIC_GA_MEASUREMENT_ID;

export function sendPageView(url) {
    if (typeof window !== 'undefined' && window.gtag) {
        window.gtag('event', 'page_view', {
            page_path: url,
            page_location: window.location.href,
            page_title: document.title
        });
    }
}

export function sendCustomEvent(eventName, parameters = {}) {
    if (typeof window !== 'undefined' && window.gtag) {
        window.gtag('event', eventName, parameters);
    }
}
Enter fullscreen mode Exit fullscreen mode

src/routes/+layout.svelte

<script>
    import { onMount } from 'svelte';
    import { afterNavigate } from '$app/navigation';
    import { sendPageView } from '$lib/analytics.js';

    onMount(() => {
        // Send initial page view
        sendPageView(window.location.pathname + window.location.search);

        // Set up navigation tracking
        afterNavigate((nav) => {
            if (nav.to?.url) {
                const newPath = nav.to.url.pathname + nav.to.url.search;
                sendPageView(newPath);
            }
        });
    });
</script>

<slot />
Enter fullscreen mode Exit fullscreen mode

.env

PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
Enter fullscreen mode Exit fullscreen mode

Testing Checklist

  • [ ] GA script loads in browser (check Network tab)
  • [ ] Initial page view is tracked
  • [ ] Client-side navigation is tracked
  • [ ] No duplicate page views
  • [ ] Custom events work (if implemented)
  • [ ] Works in production environment

Additional Resources


Note: This setup ensures that all page views are tracked, including the landing page and client-side navigation, which is essential for SPAs like SvelteKit applications.

Top comments (0)