[backport cloud/1.41] feat: add SHA-256 hashed email to GTM dataLayer for sign_up/login events (#10637)

Backport of #10591 to `cloud/1.41`

Conflict resolution: adapted the two new email-hashing tests to use the
cloud/1.41 test style (direct `new GtmTelemetryProvider()` with inline
config) since the helper functions (`createInitializedProvider`,
`lastDataLayerEntry`) from #9770 were never backported to this branch.

All 6 tests pass locally.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10637-backport-cloud-1-41-feat-add-SHA-256-hashed-email-to-GTM-dataLayer-for-sign_up-login--3316d73d365081638938f3a5653d972e)
by [Unito](https://www.unito.io)
This commit is contained in:
Christian Byrne
2026-03-27 19:40:19 -07:00
committed by GitHub
parent 6869b5c6db
commit 8983fdd49d
4 changed files with 61 additions and 4 deletions

View File

@@ -80,4 +80,50 @@ describe('GtmTelemetryProvider', () => {
event: 'subscription_success'
})
})
it('pushes normalized email as user_data before auth event', () => {
window.__CONFIG__ = {
gtm_container_id: 'GTM-TEST123'
}
const provider = new GtmTelemetryProvider()
provider.trackAuth({
method: 'email',
is_new_user: true,
user_id: 'uid-123',
email: ' Test@Example.com '
})
const dl = window.dataLayer as Record<string, unknown>[]
const userData = dl.find((entry) => 'user_data' in entry)
expect(userData).toMatchObject({
user_data: { email: 'test@example.com' }
})
// Verify user_data is pushed before the sign_up event
const userDataIndex = dl.findIndex((entry) => 'user_data' in entry)
const signUpIndex = dl.findIndex(
(entry) => (entry as Record<string, unknown>).event === 'sign_up'
)
expect(userDataIndex).toBeLessThan(signUpIndex)
})
it('does not push user_data when email is absent', () => {
window.__CONFIG__ = {
gtm_container_id: 'GTM-TEST123'
}
const provider = new GtmTelemetryProvider()
provider.trackAuth({
method: 'google',
is_new_user: false,
user_id: 'uid-456'
})
const dl = window.dataLayer as Record<string, unknown>[]
const userData = dl.find((entry) => 'user_data' in entry)
expect(userData).toBeUndefined()
})
})

View File

@@ -103,6 +103,12 @@ export class GtmTelemetryProvider implements TelemetryProvider {
...(metadata.user_id ? { user_id: metadata.user_id } : {})
}
if (metadata.email) {
window.dataLayer?.push({
user_data: { email: metadata.email.trim().toLowerCase() }
})
}
if (metadata.is_new_user) {
this.pushEvent('sign_up', basePayload)
return

View File

@@ -24,6 +24,7 @@ export interface AuthMetadata {
method?: 'email' | 'google' | 'github'
is_new_user?: boolean
user_id?: string
email?: string
referrer_url?: string
utm_source?: string
utm_medium?: string

View File

@@ -350,7 +350,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
useTelemetry()?.trackAuth({
method: 'email',
is_new_user: false,
user_id: result.user.uid
user_id: result.user.uid,
email: result.user.email ?? undefined
})
}
@@ -371,7 +372,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
useTelemetry()?.trackAuth({
method: 'email',
is_new_user: true,
user_id: result.user.uid
user_id: result.user.uid,
email: result.user.email ?? undefined
})
}
@@ -392,7 +394,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
method: 'google',
is_new_user:
options?.isNewUser || additionalUserInfo?.isNewUser || false,
user_id: result.user.uid
user_id: result.user.uid,
email: result.user.email ?? undefined
})
}
@@ -413,7 +416,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
method: 'github',
is_new_user:
options?.isNewUser || additionalUserInfo?.isNewUser || false,
user_id: result.user.uid
user_id: result.user.uid,
email: result.user.email ?? undefined
})
}