Skip to content

Commit 20aa9d5

Browse files
committed
fix(googleAnalytics): support customer ids
Fixes #246
1 parent c079f51 commit 20aa9d5

File tree

4 files changed

+131
-6
lines changed

4 files changed

+131
-6
lines changed

docs/content/scripts/analytics/google-analytics.md

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,49 @@ You must provide the options when setting up the script for the first time.
142142
```ts
143143
export const GoogleAnalyticsOptions = object({
144144
/**
145-
* The Google Analytics ID.
145+
* The Google Analytics ID. Optional - allows loading gtag.js without initial configuration.
146146
*/
147-
id: string(),
147+
id: optional(string()),
148148
/**
149149
* The datalayer's name you want it to be associated with
150150
*/
151151
l: optional(string())
152152
})
153153
```
154154

155+
### Customer/Consumer ID Tracking
156+
157+
For e-commerce or multi-tenant applications where you need to track customer-specific analytics alongside your main tracking:
158+
159+
```vue [ProductPage.vue]
160+
<script setup lang="ts">
161+
// Product page with customer-specific tracking
162+
const route = useRoute()
163+
const pageData = await $fetch(`/api/product/${route.params.id}`)
164+
165+
// Load gtag with a custom dataLayer name for customer tracking
166+
const { proxy: customerGtag, load } = useScriptGoogleAnalytics({
167+
key: 'gtag-customer',
168+
l: 'customerDataLayer', // Custom dataLayer name
169+
})
170+
171+
// Configure customer's tracking ID when available
172+
const consumerGtagId = computed(() => pageData?.gtag)
173+
174+
if (consumerGtagId.value) {
175+
// Configure the customer's GA4 property
176+
customerGtag.gtag('config', consumerGtagId.value)
177+
178+
// Send customer-specific events
179+
customerGtag.gtag('event', 'product_view', {
180+
item_id: pageData.id,
181+
customer_id: pageData.customerId,
182+
value: pageData.price
183+
})
184+
}
185+
</script>
186+
```
187+
155188
## Example
156189

157190
Using Google Analytics only in production while using `gtag` to send a conversion event.

playground/pages/features/custom-registry.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ const { proxy, status } = useScriptMyCustomScript({
77
apiKey: 'demo-api-key-123',
88
scriptOptions: {
99
trigger: 'onNuxtReady',
10-
// Add some DevTools metadata for demonstration
11-
performanceMarkFeature: 'custom-registry-demo',
1210
},
1311
})
1412
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<script lang="ts" setup>
2+
import { useHead } from '#imports'
3+
4+
useHead({
5+
title: 'Google Analytics - Optional ID Loading',
6+
})
7+
8+
// Simulate dynamic customer data
9+
const customerData = ref<{ gtagId?: string }>({})
10+
const isCustomerLoaded = ref(false)
11+
12+
// Load gtag.js without initial ID
13+
const { proxy: gtagProxy, status } = useScriptGoogleAnalytics({
14+
key: 'gtag-optional',
15+
})
16+
17+
// Simulate loading customer data
18+
function loadCustomerData() {
19+
customerData.value = { gtagId: 'G-CUSTOMER123' }
20+
isCustomerLoaded.value = true
21+
22+
// Now configure gtag with the customer ID
23+
gtagProxy.gtag('config', customerData.value.gtagId!)
24+
25+
// Send a test event
26+
gtagProxy.gtag('event', 'customer_loaded', {
27+
customer_id: 'test-customer',
28+
value: 1,
29+
})
30+
}
31+
32+
// Load additional ID dynamically
33+
function loadAdditionalId() {
34+
gtagProxy.gtag('config', 'G-ADDITIONAL456')
35+
gtagProxy.gtag('event', 'additional_tracking', {
36+
source: 'dynamic_load',
37+
})
38+
}
39+
40+
// Test sending events
41+
function sendTestEvent() {
42+
gtagProxy.gtag('event', 'test_interaction', {
43+
event_category: 'user_action',
44+
event_label: 'button_click',
45+
})
46+
}
47+
</script>
48+
49+
<template>
50+
<div class="space-y-4 p-4">
51+
<h1 class="text-2xl font-bold">
52+
Google Analytics - Optional ID Loading
53+
</h1>
54+
55+
<div class="p-4 rounded">
56+
<h2 class="font-semibold mb-2">
57+
Status
58+
</h2>
59+
<ClientOnly>
60+
<div>Script status: {{ status }}</div>
61+
<div>Customer loaded: {{ isCustomerLoaded }}</div>
62+
<div>Customer ID: {{ customerData.gtagId || 'Not loaded' }}</div>
63+
</ClientOnly>
64+
</div>
65+
66+
<div class="space-y-2">
67+
<button
68+
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
69+
:disabled="isCustomerLoaded"
70+
@click="loadCustomerData"
71+
>
72+
{{ isCustomerLoaded ? 'Customer Data Loaded' : 'Load Customer Data' }}
73+
</button>
74+
75+
<button
76+
class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
77+
:disabled="status !== 'awaitingLoad'"
78+
@click="loadAdditionalId"
79+
>
80+
Load Additional ID
81+
</button>
82+
83+
<button
84+
class="bg-purple-500 text-white px-4 py-2 rounded hover:bg-purple-600"
85+
:disabled="!isCustomerLoaded"
86+
@click="sendTestEvent"
87+
>
88+
Send Test Event
89+
</button>
90+
</div>
91+
</div>
92+
</template>

src/runtime/registry/google-analytics.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export interface GoogleAnalyticsApi {
108108
}
109109

110110
export const GoogleAnalyticsOptions = object({
111-
id: string(), // The GA4 measurement ID (format: G-XXXXXXXX)
111+
id: optional(string()), // The GA4 measurement ID (format: G-XXXXXXXX)
112112
l: optional(string()), // Optional global name for dataLayer (defaults to 'dataLayer')
113113
})
114114

@@ -143,7 +143,9 @@ export function useScriptGoogleAnalytics<T extends GoogleAnalyticsApi>(_options?
143143
// @ts-ignore
144144
_options?.onBeforeGtagStart?.(w.gtag)
145145
w.gtag('js', new Date())
146-
w.gtag('config', (options?.id))
146+
if (options?.id) {
147+
w.gtag('config', (options?.id))
148+
}
147149
},
148150
}
149151
}, _options)

0 commit comments

Comments
 (0)