mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-28 00:07:32 +00:00
feat: fire subscription_success telemetry on subscription activation (#10186)
## Summary
Fire a client-side `subscription_success` event to GTM when a
subscription activates, enabling LinkedIn and Meta conversion tracking
tags.
## Changes
- **What**: Wire `trackMonthlySubscriptionSucceeded()` into both
subscription detection paths (legacy dialog watcher + workspace
billingOperationStore). This method existed but had zero call sites
(dead code). The event name remains `subscription_success` (not
`purchase`) to avoid double-counting with the server-side GA4
Measurement Protocol purchase event and the existing Google Ads Purchase
conversion tag in GTM.
## Review Focus
- billingOperationStore only fires telemetry for `subscription`
operations, not `topup`.
- Legacy flow: telemetry fires in the existing `isActiveSubscription`
watcher, before `emit("close", true)`.
- Workspace flow: telemetry fires in `handleSuccess()` after status
update but before billing context refresh.
- No event name change: `subscription_success` was the original name and
avoids collision with the server-side `purchase` event.
---------
Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
This commit is contained in:
@@ -236,6 +236,7 @@ watch(
|
||||
() => isActiveSubscription.value,
|
||||
(isActive) => {
|
||||
if (isActive && showCustomPricingTable.value) {
|
||||
telemetry?.trackMonthlySubscriptionSucceeded()
|
||||
emit('close', true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,14 @@ describe('GtmTelemetryProvider', () => {
|
||||
expect(lastDataLayerEntry()).toMatchObject({ event: 'select_promotion' })
|
||||
})
|
||||
|
||||
it('pushes subscription_success for subscription activation', () => {
|
||||
const provider = createInitializedProvider()
|
||||
provider.trackMonthlySubscriptionSucceeded()
|
||||
expect(lastDataLayerEntry()).toMatchObject({
|
||||
event: 'subscription_success'
|
||||
})
|
||||
})
|
||||
|
||||
it('pushes run_workflow with trigger_source', () => {
|
||||
const provider = createInitializedProvider()
|
||||
provider.trackRunButton({ trigger_source: 'button' })
|
||||
|
||||
@@ -165,6 +165,10 @@ export class GtmTelemetryProvider implements TelemetryProvider {
|
||||
this.pushEvent('signup_opened')
|
||||
}
|
||||
|
||||
trackMonthlySubscriptionSucceeded(): void {
|
||||
this.pushEvent('subscription_success')
|
||||
}
|
||||
|
||||
trackRunButton(options?: {
|
||||
subscribe_to_run?: boolean
|
||||
trigger_source?: ExecutionTriggerSource
|
||||
|
||||
@@ -47,6 +47,14 @@ vi.mock('@/stores/dialogStore', () => ({
|
||||
})
|
||||
}))
|
||||
|
||||
const mockTrackMonthlySubscriptionSucceeded = vi.fn()
|
||||
|
||||
vi.mock('@/platform/telemetry', () => ({
|
||||
useTelemetry: () => ({
|
||||
trackMonthlySubscriptionSucceeded: mockTrackMonthlySubscriptionSucceeded
|
||||
})
|
||||
}))
|
||||
|
||||
import { workspaceApi } from '@/platform/workspace/api/workspaceApi'
|
||||
|
||||
import { useBillingOperationStore } from './billingOperationStore'
|
||||
@@ -159,6 +167,37 @@ describe('billingOperationStore', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('fires purchase telemetry on subscription success', async () => {
|
||||
vi.mocked(workspaceApi.getBillingOpStatus).mockResolvedValue({
|
||||
id: 'op-1',
|
||||
status: 'succeeded',
|
||||
started_at: new Date().toISOString(),
|
||||
completed_at: new Date().toISOString()
|
||||
})
|
||||
|
||||
const store = useBillingOperationStore()
|
||||
store.startOperation('op-1', 'subscription')
|
||||
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
expect(mockTrackMonthlySubscriptionSucceeded).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('does not fire purchase telemetry on topup success', async () => {
|
||||
vi.mocked(workspaceApi.getBillingOpStatus).mockResolvedValue({
|
||||
id: 'op-1',
|
||||
status: 'succeeded',
|
||||
started_at: new Date().toISOString()
|
||||
})
|
||||
|
||||
const store = useBillingOperationStore()
|
||||
store.startOperation('op-1', 'topup')
|
||||
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
expect(mockTrackMonthlySubscriptionSucceeded).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('shows topup success message for topup operations', async () => {
|
||||
vi.mocked(workspaceApi.getBillingOpStatus).mockResolvedValue({
|
||||
id: 'op-1',
|
||||
|
||||
@@ -4,6 +4,7 @@ import { computed, ref } from 'vue'
|
||||
|
||||
import { useBillingContext } from '@/composables/billing/useBillingContext'
|
||||
import { t } from '@/i18n'
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
import { workspaceApi } from '@/platform/workspace/api/workspaceApi'
|
||||
import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog'
|
||||
@@ -133,6 +134,10 @@ export const useBillingOperationStore = defineStore('billingOperation', () => {
|
||||
updateOperationStatus(opId, 'succeeded', null)
|
||||
cleanup(opId)
|
||||
|
||||
if (operation.type === 'subscription') {
|
||||
useTelemetry()?.trackMonthlySubscriptionSucceeded()
|
||||
}
|
||||
|
||||
const billingContext = useBillingContext()
|
||||
await Promise.all([
|
||||
billingContext.fetchStatus(),
|
||||
|
||||
Reference in New Issue
Block a user