Compare commits

...

1 Commits

Author SHA1 Message Date
bymyself
c194e2c45d feat: wire high-priority GA4 events in GtmTelemetryProvider
Add GA4 dataLayer events for subscription tracking, workflow execution,
and template usage via GTM:

- trackSubscription → subscription_change
- trackMonthlySubscriptionSucceeded → subscription_success
- trackRunButton → run_workflow
- trackWorkflowExecution → workflow_execution
- trackExecutionError → execution_error
- trackAddApiCreditButtonClicked → add_credit_clicked
- trackTemplate → template_used

Each event requires a corresponding GA4 Event tag in GTM (GTM-NP9JM6K7)
to forward to GA4. Follow the pattern in docs/gtm-ga4-event-tags.md.
2026-03-12 05:27:49 -07:00
2 changed files with 129 additions and 0 deletions

View File

@@ -66,4 +66,89 @@ describe('GtmTelemetryProvider', () => {
expect(gtagScripts).toHaveLength(1)
})
describe('GA4 event methods', () => {
let provider: GtmTelemetryProvider
beforeEach(() => {
window.__CONFIG__ = { gtm_container_id: 'GTM-TEST123' }
provider = new GtmTelemetryProvider()
})
it('pushes subscription_change event', () => {
provider.trackSubscription('subscribe_clicked')
expect(window.dataLayer).toContainEqual(
expect.objectContaining({
event: 'subscription_change',
action: 'subscribe_clicked'
})
)
})
it('pushes subscription_success event', () => {
provider.trackMonthlySubscriptionSucceeded()
expect(window.dataLayer).toContainEqual(
expect.objectContaining({ event: 'subscription_success' })
)
})
it('pushes run_workflow event with trigger source', () => {
provider.trackRunButton({
subscribe_to_run: true,
trigger_source: 'button'
})
expect(window.dataLayer).toContainEqual(
expect.objectContaining({
event: 'run_workflow',
subscribe_to_run: true,
trigger_source: 'button'
})
)
})
it('pushes workflow_execution event', () => {
provider.trackWorkflowExecution()
expect(window.dataLayer).toContainEqual(
expect.objectContaining({ event: 'workflow_execution' })
)
})
it('pushes execution_error event', () => {
provider.trackExecutionError({
jobId: 'job-1',
nodeType: 'KSampler',
error: 'OOM'
})
expect(window.dataLayer).toContainEqual(
expect.objectContaining({
event: 'execution_error',
node_type: 'KSampler',
error: 'OOM'
})
)
})
it('pushes add_credit_clicked event', () => {
provider.trackAddApiCreditButtonClicked()
expect(window.dataLayer).toContainEqual(
expect.objectContaining({ event: 'add_credit_clicked' })
)
})
it('pushes template_used event', () => {
provider.trackTemplate({
workflow_name: 'SDXL Basic',
template_source: 'library',
template_category: 'image_generation'
})
expect(window.dataLayer).toContainEqual(
expect.objectContaining({
event: 'template_used',
workflow_name: 'SDXL Basic',
template_source: 'library',
template_category: 'image_generation'
})
)
})
})
})

View File

@@ -1,7 +1,10 @@
import type {
AuthMetadata,
BeginCheckoutMetadata,
ExecutionErrorMetadata,
ExecutionTriggerSource,
PageViewMetadata,
TemplateMetadata,
TelemetryProvider
} from '../../types'
@@ -114,4 +117,45 @@ export class GtmTelemetryProvider implements TelemetryProvider {
trackBeginCheckout(metadata: BeginCheckoutMetadata): void {
this.pushEvent('begin_checkout', metadata)
}
trackSubscription(event: 'modal_opened' | 'subscribe_clicked'): void {
this.pushEvent('subscription_change', { action: event })
}
trackMonthlySubscriptionSucceeded(): void {
this.pushEvent('subscription_success')
}
trackRunButton(options?: {
subscribe_to_run?: boolean
trigger_source?: ExecutionTriggerSource
}): void {
this.pushEvent('run_workflow', {
subscribe_to_run: options?.subscribe_to_run,
trigger_source: options?.trigger_source
})
}
trackWorkflowExecution(): void {
this.pushEvent('workflow_execution')
}
trackExecutionError(metadata: ExecutionErrorMetadata): void {
this.pushEvent('execution_error', {
node_type: metadata.nodeType,
error: metadata.error
})
}
trackAddApiCreditButtonClicked(): void {
this.pushEvent('add_credit_clicked')
}
trackTemplate(metadata: TemplateMetadata): void {
this.pushEvent('template_used', {
workflow_name: metadata.workflow_name,
template_source: metadata.template_source,
template_category: metadata.template_category
})
}
}