Skip to content

Commit d651214

Browse files
committed
fix: route gtm through telemetry entrypoint (#8354)
1 parent 9691f5f commit d651214

25 files changed

+1112
-275
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: 'CI: Dist Telemetry Scan'
2+
3+
on:
4+
pull_request:
5+
branches-ignore: [wip/*, draft/*, temp/*]
6+
7+
concurrency:
8+
group: ${{ github.workflow }}-${{ github.ref }}
9+
cancel-in-progress: true
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
scan:
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
20+
21+
- name: Install pnpm
22+
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
23+
with:
24+
version: 10
25+
26+
- name: Use Node.js
27+
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
28+
with:
29+
node-version: 'lts/*'
30+
cache: 'pnpm'
31+
32+
- name: Install dependencies
33+
run: pnpm install --frozen-lockfile
34+
35+
- name: Build project
36+
run: pnpm build
37+
38+
- name: Scan dist for telemetry references
39+
run: |
40+
set -euo pipefail
41+
if rg --no-ignore -n \
42+
-g '*.html' \
43+
-g '*.js' \
44+
-e 'Google Tag Manager' \
45+
-e '(?i)\bgtm\.js\b' \
46+
-e '(?i)googletagmanager\.com/gtm\.js\\?id=' \
47+
-e '(?i)googletagmanager\.com/ns\.html\\?id=' \
48+
dist; then
49+
echo 'Telemetry references found in dist assets.'
50+
exit 1
51+
fi
52+
echo 'No telemetry references found in dist assets.'

global.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ declare const __USE_PROD_CONFIG__: boolean
77

88
interface Window {
99
__CONFIG__: {
10+
gtm_container_id?: string
1011
mixpanel_token?: string
1112
require_whitelist?: boolean
1213
subscription_required?: boolean
@@ -30,6 +31,12 @@ interface Window {
3031
badge?: string
3132
}
3233
}
34+
__ga_identity__?: {
35+
client_id?: string
36+
session_id?: string
37+
session_number?: string
38+
}
39+
dataLayer?: Array<Record<string, unknown>>
3340
}
3441

3542
interface Navigator {

src/main.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ import { i18n } from './i18n'
2525
* CRITICAL: Load remote config FIRST for cloud builds to ensure
2626
* window.__CONFIG__is available for all modules during initialization
2727
*/
28-
import { isCloud } from '@/platform/distribution/types'
28+
const isCloud = __DISTRIBUTION__ === 'cloud'
2929

3030
if (isCloud) {
3131
const { refreshRemoteConfig } =
3232
await import('@/platform/remoteConfig/refreshRemoteConfig')
3333
await refreshRemoteConfig({ useAuth: false })
34+
35+
const { initTelemetry } = await import('@/platform/telemetry/initTelemetry')
36+
await initTelemetry()
3437
}
3538

3639
const ComfyUIPreset = definePreset(Aura, {

src/platform/cloud/onboarding/CloudSubscriptionRedirectView.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ vi.mock('@/composables/useErrorHandling', () => ({
4040

4141
const subscriptionMocks = vi.hoisted(() => ({
4242
isActiveSubscription: { value: false },
43-
isInitialized: { value: true }
43+
isInitialized: { value: true },
44+
subscriptionStatus: { value: null }
4445
}))
4546

4647
vi.mock('@/platform/cloud/subscription/composables/useSubscription', () => ({

src/platform/cloud/subscription/components/PricingTable.test.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@ const mockSubscriptionTier = ref<
1414
const mockIsYearlySubscription = ref(false)
1515
const mockAccessBillingPortal = vi.fn()
1616
const mockReportError = vi.fn()
17+
const mockTrackBeginCheckout = vi.fn()
1718
const mockGetFirebaseAuthHeader = vi.fn(() =>
1819
Promise.resolve({ Authorization: 'Bearer test-token' })
1920
)
21+
const mockGetCheckoutAttribution = vi.hoisted(() => vi.fn(() => ({})))
2022

2123
vi.mock('@/platform/cloud/subscription/composables/useSubscription', () => ({
2224
useSubscription: () => ({
2325
isActiveSubscription: computed(() => mockIsActiveSubscription.value),
2426
subscriptionTier: computed(() => mockSubscriptionTier.value),
25-
isYearlySubscription: computed(() => mockIsYearlySubscription.value)
27+
isYearlySubscription: computed(() => mockIsYearlySubscription.value),
28+
subscriptionStatus: ref(null)
2629
})
2730
}))
2831

@@ -53,11 +56,22 @@ vi.mock('@/composables/useErrorHandling', () => ({
5356

5457
vi.mock('@/stores/firebaseAuthStore', () => ({
5558
useFirebaseAuthStore: () => ({
56-
getFirebaseAuthHeader: mockGetFirebaseAuthHeader
59+
getFirebaseAuthHeader: mockGetFirebaseAuthHeader,
60+
userId: 'user-123'
5761
}),
5862
FirebaseAuthStoreError: class extends Error {}
5963
}))
6064

65+
vi.mock('@/platform/telemetry', () => ({
66+
useTelemetry: () => ({
67+
trackBeginCheckout: mockTrackBeginCheckout
68+
})
69+
}))
70+
71+
vi.mock('@/platform/telemetry/utils/checkoutAttribution', () => ({
72+
getCheckoutAttribution: mockGetCheckoutAttribution
73+
}))
74+
6175
vi.mock('@/platform/distribution/types', () => ({
6276
isCloud: true
6377
}))
@@ -126,6 +140,7 @@ describe('PricingTable', () => {
126140
mockIsActiveSubscription.value = false
127141
mockSubscriptionTier.value = null
128142
mockIsYearlySubscription.value = false
143+
mockTrackBeginCheckout.mockReset()
129144
vi.mocked(global.fetch).mockResolvedValue({
130145
ok: true,
131146
json: async () => ({ checkout_url: 'https://checkout.stripe.com/test' })
@@ -148,6 +163,13 @@ describe('PricingTable', () => {
148163
await creatorButton?.trigger('click')
149164
await flushPromises()
150165

166+
expect(mockTrackBeginCheckout).toHaveBeenCalledWith({
167+
user_id: 'user-123',
168+
tier: 'creator',
169+
cycle: 'yearly',
170+
checkout_type: 'change',
171+
previous_tier: 'standard'
172+
})
151173
expect(mockAccessBillingPortal).toHaveBeenCalledWith('creator-yearly')
152174
})
153175

src/platform/cloud/subscription/components/PricingTable.vue

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ import { performSubscriptionCheckout } from '@/platform/cloud/subscription/utils
266266
import { isPlanDowngrade } from '@/platform/cloud/subscription/utils/subscriptionTierRank'
267267
import type { BillingCycle } from '@/platform/cloud/subscription/utils/subscriptionTierRank'
268268
import { isCloud } from '@/platform/distribution/types'
269+
import { useTelemetry } from '@/platform/telemetry'
270+
import { getCheckoutAttribution } from '@/platform/telemetry/utils/checkoutAttribution'
271+
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
269272
import type { components } from '@/types/comfyRegistryTypes'
270273
271274
type SubscriptionTier = components['schemas']['SubscriptionTier']
@@ -330,6 +333,8 @@ const tiers: PricingTierConfig[] = [
330333
const { n } = useI18n()
331334
const { isActiveSubscription, subscriptionTier, isYearlySubscription } =
332335
useSubscription()
336+
const telemetry = useTelemetry()
337+
const { userId } = useFirebaseAuthStore()
333338
const { accessBillingPortal, reportError } = useFirebaseAuthActions()
334339
const { wrapWithErrorHandlingAsync } = useErrorHandling()
335340
@@ -410,6 +415,19 @@ const handleSubscribe = wrapWithErrorHandlingAsync(
410415
411416
try {
412417
if (isActiveSubscription.value) {
418+
const checkoutAttribution = getCheckoutAttribution()
419+
if (userId) {
420+
telemetry?.trackBeginCheckout({
421+
user_id: userId,
422+
tier: tierKey,
423+
cycle: currentBillingCycle.value,
424+
checkout_type: 'change',
425+
...checkoutAttribution,
426+
...(currentTierKey.value
427+
? { previous_tier: currentTierKey.value }
428+
: {})
429+
})
430+
}
413431
// Pass the target tier to create a deep link to subscription update confirmation
414432
const checkoutTier = getCheckoutTier(tierKey, currentBillingCycle.value)
415433
const targetPlan = {
@@ -430,7 +448,11 @@ const handleSubscribe = wrapWithErrorHandlingAsync(
430448
await accessBillingPortal(checkoutTier)
431449
}
432450
} else {
433-
await performSubscriptionCheckout(tierKey, currentBillingCycle.value)
451+
await performSubscriptionCheckout(
452+
tierKey,
453+
currentBillingCycle.value,
454+
true
455+
)
434456
}
435457
} finally {
436458
isLoading.value = false

0 commit comments

Comments
 (0)