Skip to content

Commit 56412a4

Browse files
christian-byrneChristian ByrneDrJKLbenceruleanluclaude
authored
[Backport to rh-test] fix(telemetry): remove redundant run tracking; keep click analytics + single execution event (#6552)
## Summary Manual backport of #6518 to the `rh-test` branch. Deduplicates workflow run telemetry and keeps a single source of truth for execution while retaining click analytics and attributing initiator source. - Keep execution tracking in one place via `trackWorkflowExecution()` - Keep click analytics via `trackRunButton(...)` - Attribute initiator with `trigger_source` = 'button' | 'keybinding' | 'legacy_ui' - Remove pre-tracking from keybindings to avoid double/triple counting - Update legacy UI buttons to emit both click + execution events ## Backport Notes This backport required manual conflict resolution in: - `src/components/actionbar/ComfyRunButton/ComfyQueueButton.vue` - Added batchCount tracking and trigger_source metadata - `src/composables/useCoreCommands.ts` - Added error handling and execution tracking - `src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts` - Updated trackRunButton signature with trigger_source support Additionally added: - `trackUiButtonClicked` method to TelemetryProvider interface - `UiButtonClickMetadata` type definition - `UI_BUTTON_CLICKED` event constant All conflicts resolved intelligently to maintain the intent of the original PR while adapting to the rh-test branch codebase. ## Original PR - Original PR: #6518 - Original commit: 6fe88db ## Testing - ✅ Typecheck passed - ✅ Pre-commit hooks passed (lint, format) - ✅ All conflicts resolved ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6552-Backport-to-rh-test-fix-telemetry-remove-redundant-run-tracking-keep-click-analytics-2a06d73d365081f78e4ad46a16be69f1) by [Unito](https://www.unito.io) --------- Co-authored-by: Christian Byrne <[email protected]> Co-authored-by: Alexander Brown <[email protected]> Co-authored-by: Benjamin Lu <[email protected]> Co-authored-by: Claude <[email protected]> Co-authored-by: Christian Byrne <[email protected]>
1 parent 044b675 commit 56412a4

File tree

10 files changed

+128
-57
lines changed

10 files changed

+128
-57
lines changed

src/components/actionbar/ComfyRunButton/ComfyQueueButton.vue

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ import BatchCountEdit from '../BatchCountEdit.vue'
100100
101101
const workspaceStore = useWorkspaceStore()
102102
const queueCountStore = storeToRefs(useQueuePendingTaskCountStore())
103-
const { mode: queueMode } = storeToRefs(useQueueSettingsStore())
103+
const { mode: queueMode, batchCount } = storeToRefs(useQueueSettingsStore())
104104
105105
const { t } = useI18n()
106106
const queueModeMenuItemLookup = computed(() => {
@@ -158,9 +158,18 @@ const queuePrompt = async (e: Event) => {
158158
? 'Comfy.QueuePromptFront'
159159
: 'Comfy.QueuePrompt'
160160
161-
useTelemetry()?.trackRunButton({ subscribe_to_run: false })
161+
if (batchCount.value > 1) {
162+
useTelemetry()?.trackUiButtonClicked({
163+
button_id: 'queue_run_multiple_batches_submitted'
164+
})
165+
}
162166
163-
await commandStore.execute(commandId)
167+
await commandStore.execute(commandId, {
168+
metadata: {
169+
subscribe_to_run: false,
170+
trigger_source: 'button'
171+
}
172+
})
164173
}
165174
</script>
166175

src/composables/useCoreCommands.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { useSubscription } from '@/platform/cloud/subscription/composables/useSu
2121
import { useSettingStore } from '@/platform/settings/settingStore'
2222
import { SUPPORT_URL } from '@/platform/support/config'
2323
import { useTelemetry } from '@/platform/telemetry'
24+
import type { ExecutionTriggerSource } from '@/platform/telemetry/types'
2425
import { useToastStore } from '@/platform/updates/common/toastStore'
2526
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
2627
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
@@ -465,7 +466,11 @@ export function useCoreCommands(): ComfyCommand[] {
465466
label: 'Queue Prompt',
466467
versionAdded: '1.3.7',
467468
category: 'essentials' as const,
468-
function: async () => {
469+
function: async (metadata?: {
470+
subscribe_to_run?: boolean
471+
trigger_source?: ExecutionTriggerSource
472+
}) => {
473+
useTelemetry()?.trackRunButton(metadata)
469474
if (!isActiveSubscription.value) {
470475
showSubscriptionDialog()
471476
return
@@ -484,7 +489,11 @@ export function useCoreCommands(): ComfyCommand[] {
484489
label: 'Queue Prompt (Front)',
485490
versionAdded: '1.3.7',
486491
category: 'essentials' as const,
487-
function: async () => {
492+
function: async (metadata?: {
493+
subscribe_to_run?: boolean
494+
trigger_source?: ExecutionTriggerSource
495+
}) => {
496+
useTelemetry()?.trackRunButton(metadata)
488497
if (!isActiveSubscription.value) {
489498
showSubscriptionDialog()
490499
return
@@ -502,7 +511,11 @@ export function useCoreCommands(): ComfyCommand[] {
502511
icon: 'pi pi-play',
503512
label: 'Queue Selected Output Nodes',
504513
versionAdded: '1.19.6',
505-
function: async () => {
514+
function: async (metadata?: {
515+
subscribe_to_run?: boolean
516+
trigger_source?: ExecutionTriggerSource
517+
}) => {
518+
useTelemetry()?.trackRunButton(metadata)
506519
if (!isActiveSubscription.value) {
507520
showSubscriptionDialog()
508521
return
@@ -525,6 +538,17 @@ export function useCoreCommands(): ComfyCommand[] {
525538
// Get execution IDs for all selected output nodes and their descendants
526539
const executionIds =
527540
getExecutionIdsForSelectedNodes(selectedOutputNodes)
541+
542+
if (executionIds.length === 0) {
543+
toastStore.add({
544+
severity: 'error',
545+
summary: t('toastMessages.failedToQueue'),
546+
detail: t('toastMessages.failedExecutionPathResolution'),
547+
life: 3000
548+
})
549+
return
550+
}
551+
useTelemetry()?.trackWorkflowExecution()
528552
await app.queuePrompt(0, batchCount, executionIds)
529553
}
530554
},

src/extensions/core/groupNode.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,21 +1742,22 @@ const ext: ComfyExtension = {
17421742
label: 'Convert selected nodes to group node',
17431743
icon: 'pi pi-sitemap',
17441744
versionAdded: '1.3.17',
1745-
function: convertSelectedNodesToGroupNode
1745+
function: () => convertSelectedNodesToGroupNode()
17461746
},
17471747
{
17481748
id: 'Comfy.GroupNode.UngroupSelectedGroupNodes',
17491749
label: 'Ungroup selected group nodes',
17501750
icon: 'pi pi-sitemap',
17511751
versionAdded: '1.3.17',
1752-
function: ungroupSelectedGroupNodes
1752+
function: () => ungroupSelectedGroupNodes()
17531753
},
17541754
{
17551755
id: 'Comfy.GroupNode.ManageGroupNodes',
17561756
label: 'Manage group nodes',
17571757
icon: 'pi pi-cog',
17581758
versionAdded: '1.3.17',
1759-
function: manageGroupNodes
1759+
function: (...args: unknown[]) =>
1760+
manageGroupNodes(args[0] as string | undefined)
17601761
}
17611762
],
17621763
keybindings: [

src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
ExecutionContext,
1717
ExecutionErrorMetadata,
1818
ExecutionSuccessMetadata,
19+
ExecutionTriggerSource,
1920
HelpCenterClosedMetadata,
2021
HelpCenterOpenedMetadata,
2122
HelpResourceClickedMetadata,
@@ -32,6 +33,7 @@ import type {
3233
TemplateLibraryClosedMetadata,
3334
TemplateLibraryMetadata,
3435
TemplateMetadata,
36+
UiButtonClickMetadata,
3537
WorkflowCreatedMetadata,
3638
WorkflowImportMetadata
3739
} from '../../types'
@@ -59,6 +61,7 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
5961
private mixpanel: OverridedMixpanel | null = null
6062
private eventQueue: QueuedEvent[] = []
6163
private isInitialized = false
64+
private lastTriggerSource: ExecutionTriggerSource | undefined
6265

6366
// Onboarding mode - starts true, set to false when app is fully ready
6467
private isOnboardingMode = true
@@ -354,7 +357,10 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
354357
clearTopupUtil()
355358
}
356359

357-
trackRunButton(options?: { subscribe_to_run?: boolean }): void {
360+
trackRunButton(options?: {
361+
subscribe_to_run?: boolean
362+
trigger_source?: ExecutionTriggerSource
363+
}): void {
358364
if (this.isOnboardingMode) {
359365
// During onboarding, track basic run button click without workflow context
360366
this.trackEvent(TelemetryEvents.RUN_BUTTON_CLICKED, {
@@ -365,7 +371,8 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
365371
total_node_count: 0,
366372
subgraph_count: 0,
367373
has_api_nodes: false,
368-
api_node_names: []
374+
api_node_names: [],
375+
trigger_source: options?.trigger_source
369376
})
370377
return
371378
}
@@ -380,20 +387,14 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
380387
total_node_count: executionContext.total_node_count,
381388
subgraph_count: executionContext.subgraph_count,
382389
has_api_nodes: executionContext.has_api_nodes,
383-
api_node_names: executionContext.api_node_names
390+
api_node_names: executionContext.api_node_names,
391+
trigger_source: options?.trigger_source
384392
}
385393

394+
this.lastTriggerSource = options?.trigger_source
386395
this.trackEvent(TelemetryEvents.RUN_BUTTON_CLICKED, runButtonProperties)
387396
}
388397

389-
trackRunTriggeredViaKeybinding(): void {
390-
this.trackEvent(TelemetryEvents.RUN_TRIGGERED_KEYBINDING)
391-
}
392-
393-
trackRunTriggeredViaMenu(): void {
394-
this.trackEvent(TelemetryEvents.RUN_TRIGGERED_MENU)
395-
}
396-
397398
trackSurvey(
398399
stage: 'opened' | 'submitted',
399400
responses?: SurveyResponses
@@ -501,6 +502,10 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
501502
this.trackEvent(TelemetryEvents.WORKFLOW_CREATED, metadata)
502503
}
503504

505+
trackUiButtonClicked(metadata: UiButtonClickMetadata): void {
506+
this.trackEvent(TelemetryEvents.UI_BUTTON_CLICKED, metadata)
507+
}
508+
504509
trackWorkflowExecution(): void {
505510
if (this.isOnboardingMode) {
506511
// During onboarding, track basic execution without workflow context
@@ -518,7 +523,12 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
518523
}
519524

520525
const context = this.getExecutionContext()
521-
this.trackEvent(TelemetryEvents.EXECUTION_START, context)
526+
const eventContext: ExecutionContext = {
527+
...context,
528+
trigger_source: this.lastTriggerSource ?? 'unknown'
529+
}
530+
this.trackEvent(TelemetryEvents.EXECUTION_START, eventContext)
531+
this.lastTriggerSource = undefined
522532
}
523533

524534
trackExecutionError(metadata: ExecutionErrorMetadata): void {

src/platform/telemetry/types.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export interface RunButtonProperties {
4848
subgraph_count: number
4949
has_api_nodes: boolean
5050
api_node_names: string[]
51+
trigger_source?: ExecutionTriggerSource
5152
}
5253

5354
/**
@@ -70,6 +71,7 @@ export interface ExecutionContext {
7071
total_node_count: number
7172
has_api_nodes: boolean
7273
api_node_names: string[]
74+
trigger_source?: ExecutionTriggerSource
7375
}
7476

7577
/**
@@ -193,6 +195,14 @@ export interface TemplateFilterMetadata {
193195
total_count: number
194196
}
195197

198+
/**
199+
* UI button click tracking metadata
200+
*/
201+
export interface UiButtonClickMetadata {
202+
/** Canonical identifier for the button (e.g., "comfy_logo") */
203+
button_id: string
204+
}
205+
196206
/**
197207
* Help center opened metadata
198208
*/
@@ -250,9 +260,10 @@ export interface TelemetryProvider {
250260
trackAddApiCreditButtonClicked(): void
251261
trackApiCreditTopupButtonPurchaseClicked(amount: number): void
252262
trackApiCreditTopupSucceeded(): void
253-
trackRunButton(options?: { subscribe_to_run?: boolean }): void
254-
trackRunTriggeredViaKeybinding(): void
255-
trackRunTriggeredViaMenu(): void
263+
trackRunButton(options?: {
264+
subscribe_to_run?: boolean
265+
trigger_source?: ExecutionTriggerSource
266+
}): void
256267

257268
// Credit top-up tracking (composition with internal utilities)
258269
startTopupTracking(): void
@@ -284,6 +295,9 @@ export interface TelemetryProvider {
284295
// Template filter tracking events
285296
trackTemplateFilterChanged(metadata: TemplateFilterMetadata): void
286297

298+
// Generic UI button click events
299+
trackUiButtonClicked(metadata: UiButtonClickMetadata): void
300+
287301
// Help center events
288302
trackHelpCenterOpened(metadata: HelpCenterOpenedMetadata): void
289303
trackHelpResourceClicked(metadata: HelpResourceClickedMetadata): void
@@ -321,8 +335,6 @@ export const TelemetryEvents = {
321335

322336
// Subscription Flow
323337
RUN_BUTTON_CLICKED: 'app:run_button_click',
324-
RUN_TRIGGERED_KEYBINDING: 'app:run_triggered_keybinding',
325-
RUN_TRIGGERED_MENU: 'app:run_triggered_menu',
326338
SUBSCRIPTION_REQUIRED_MODAL_OPENED: 'app:subscription_required_modal_opened',
327339
SUBSCRIBE_NOW_BUTTON_CLICKED: 'app:subscribe_now_button_clicked',
328340
MONTHLY_SUBSCRIPTION_SUCCEEDED: 'app:monthly_subscription_succeeded',
@@ -368,12 +380,21 @@ export const TelemetryEvents = {
368380
// Execution Lifecycle
369381
EXECUTION_START: 'execution_start',
370382
EXECUTION_ERROR: 'execution_error',
371-
EXECUTION_SUCCESS: 'execution_success'
383+
EXECUTION_SUCCESS: 'execution_success',
384+
385+
// Generic UI Button Click
386+
UI_BUTTON_CLICKED: 'app:ui_button_clicked'
372387
} as const
373388

374389
export type TelemetryEventName =
375390
(typeof TelemetryEvents)[keyof typeof TelemetryEvents]
376391

392+
export type ExecutionTriggerSource =
393+
| 'button'
394+
| 'keybinding'
395+
| 'legacy_ui'
396+
| 'unknown'
397+
377398
/**
378399
* Union type for all possible telemetry event properties
379400
*/
@@ -394,6 +415,7 @@ export type TelemetryEventProperties =
394415
| NodeSearchMetadata
395416
| NodeSearchResultMetadata
396417
| TemplateFilterMetadata
418+
| UiButtonClickMetadata
397419
| HelpCenterOpenedMetadata
398420
| HelpResourceClickedMetadata
399421
| HelpCenterClosedMetadata

src/scripts/ui.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,8 @@ export class ComfyUI {
480480
textContent: 'Queue Prompt',
481481
onclick: () => {
482482
if (isCloud) {
483-
useTelemetry()?.trackRunTriggeredViaMenu()
483+
useTelemetry()?.trackRunButton({ trigger_source: 'legacy_ui' })
484+
useTelemetry()?.trackWorkflowExecution()
484485
}
485486
app.queuePrompt(0, this.batchCount)
486487
}
@@ -587,7 +588,8 @@ export class ComfyUI {
587588
textContent: 'Queue Front',
588589
onclick: () => {
589590
if (isCloud) {
590-
useTelemetry()?.trackRunTriggeredViaMenu()
591+
useTelemetry()?.trackRunButton({ trigger_source: 'legacy_ui' })
592+
useTelemetry()?.trackWorkflowExecution()
591593
}
592594
app.queuePrompt(-1, this.batchCount)
593595
}

src/services/keybindingService.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { CORE_KEYBINDINGS } from '@/constants/coreKeybindings'
2-
import { isCloud } from '@/platform/distribution/types'
32
import { useSettingStore } from '@/platform/settings/settingStore'
4-
import { useTelemetry } from '@/platform/telemetry'
53
import { app } from '@/scripts/app'
64
import { useCommandStore } from '@/stores/commandStore'
75
import { useDialogStore } from '@/stores/dialogStore'
@@ -66,15 +64,20 @@ export const useKeybindingService = () => {
6664

6765
// Prevent default browser behavior first, then execute the command
6866
event.preventDefault()
69-
if (
70-
isCloud &&
71-
(keybinding.commandId === 'Comfy.QueuePrompt' ||
72-
keybinding.commandId === 'Comfy.QueuePromptFront' ||
73-
keybinding.commandId === 'Comfy.QueueSelectedOutputNodes')
74-
) {
75-
useTelemetry()?.trackRunTriggeredViaKeybinding()
67+
const runCommandIds = new Set([
68+
'Comfy.QueuePrompt',
69+
'Comfy.QueuePromptFront',
70+
'Comfy.QueueSelectedOutputNodes'
71+
])
72+
if (runCommandIds.has(keybinding.commandId)) {
73+
await commandStore.execute(keybinding.commandId, {
74+
metadata: {
75+
trigger_source: 'keybinding'
76+
}
77+
})
78+
} else {
79+
await commandStore.execute(keybinding.commandId)
7680
}
77-
await commandStore.execute(keybinding.commandId)
7881
return
7982
}
8083

0 commit comments

Comments
 (0)