[backport cloud/1.42] feat: fire subscription_success telemetry on subscription activation (#10186) (#10594)

Backport of #10186 to cloud/1.42.

Fires a client-side `subscription_success` event to GTM when a
subscription activates, enabling LinkedIn and Meta conversion tracking
tags.

Cherry-picked from merge commit 6c14802.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10594-backport-cloud-1-42-feat-fire-subscription_success-telemetry-on-subscription-activati-3306d73d3650812b9e5adc34369146d2)
by [Unito](https://www.unito.io)

Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
This commit is contained in:
Christian Byrne
2026-03-26 19:45:49 -07:00
committed by GitHub
parent 7758099c4b
commit 8312d2af4e
5 changed files with 57 additions and 0 deletions

View File

@@ -236,6 +236,7 @@ watch(
() => isActiveSubscription.value,
(isActive) => {
if (isActive && showCustomPricingTable.value) {
telemetry?.trackMonthlySubscriptionSucceeded()
emit('close', true)
}
}

View File

@@ -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' })

View File

@@ -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

View File

@@ -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',

View File

@@ -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(),