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
- A Google Analytics 4 property set up
- Your GA4 Measurement ID (format:
G-XXXXXXXXXX
) - 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>
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);
}
}
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 />
Step 4: Environment Variables (Optional but Recommended)
For better security and flexibility, use environment variables:
- Create or update your
.env
file:
PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
- 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>
- 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
Step 5: Verify Your Setup
Test in Development
- Open your browser's developer tools
- Go to the Network tab
- Navigate through your site
- Look for requests to
google-analytics.com
orgoogletagmanager.com
Test in Production
- Deploy your site
- Go to Google Analytics → Realtime → Events
- Navigate through your site
- 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: ['..']
}
}
});
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
});
}
}
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
});
}
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
}
]
});
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>
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);
}
}
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 />
.env
PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
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)