Files
ComfyUI_frontend/src/platform/telemetry/providers/cloud/GtmTelemetryProvider.ts
Subagent 5 c0ee82014d feat: add TelemetryRegistry for multi-provider dispatch
- Add TelemetryRegistry that dispatches to multiple providers
- Add GtmTelemetryProvider for GTM/GA4 integration
- Convert TelemetryProvider methods to optional (providers implement what they need)
- Add TelemetryDispatcher type (Required<TelemetryProvider>) for call sites
- Dynamically import providers to ensure tree-shaking in OSS builds
- Track page_view, sign_up, login, and purchase events via GTM
- Remove gtm.ts in favor of GtmTelemetryProvider

Amp-Thread-ID: https://ampcode.com/threads/T-019c07ca-7748-77c8-b15b-d79d42779f8f
Co-authored-by: Amp <amp@ampcode.com>
2026-01-28 20:17:19 -08:00

94 lines
2.3 KiB
TypeScript

import type {
AuthMetadata,
PageViewMetadata,
TelemetryProvider
} from '../../types'
declare global {
interface Window {
dataLayer?: Record<string, unknown>[]
}
}
/**
* Google Tag Manager telemetry provider.
* Pushes events to the GTM dataLayer for GA4 and marketing integrations.
*
* Only implements events relevant to GTM/GA4 tracking.
* Other methods are no-ops (not implemented since interface is optional).
*/
export class GtmTelemetryProvider implements TelemetryProvider {
private dataLayer: Record<string, unknown>[] = []
private initialized = false
constructor() {
this.initialize()
}
private initialize(): void {
if (typeof window === 'undefined') return
const gtmId = window.__CONFIG__?.gtm_id
if (!gtmId) {
if (import.meta.env.MODE === 'development') {
console.warn('[GTM] No GTM ID configured, skipping initialization')
}
return
}
window.dataLayer = window.dataLayer || []
this.dataLayer = window.dataLayer
this.dataLayer.push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
})
const script = document.createElement('script')
script.async = true
script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`
document.head.insertBefore(script, document.head.firstChild)
this.initialized = true
}
private pushEvent(event: string, properties?: Record<string, unknown>): void {
if (!this.initialized) return
this.dataLayer.push({ event, ...properties })
}
trackPageView(pageName: string, properties?: PageViewMetadata): void {
this.pushEvent('page_view', {
page_title: pageName,
page_location: properties?.path,
page_referrer: properties?.referrer
})
}
trackAuth(metadata: AuthMetadata): void {
if (metadata.is_new_user) {
this.pushEvent('sign_up', {
method: metadata.method
})
} else {
this.pushEvent('login', {
method: metadata.method
})
}
}
trackMonthlySubscriptionSucceeded(): void {
this.pushEvent('purchase', {
currency: 'USD',
items: [{ item_name: 'Monthly Subscription' }]
})
}
trackApiCreditTopupSucceeded(): void {
this.pushEvent('purchase', {
currency: 'USD',
items: [{ item_name: 'API Credits' }]
})
}
}