From dad2d803df6246bb4f71e4a6fb11371f83a7566e Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Sat, 1 Nov 2025 02:42:36 -0700 Subject: [PATCH] feat(telemetry): add unified run_triggered event for all run initiations (#6499) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary - Add new telemetry event: `app:run_triggered` with `{ trigger_source: 'button' | 'keybinding' | 'menu' }`. - Instrument all run initiation paths: - UI Queue button emits `run_triggered` (source `button`) and keeps emitting `run_button_click` for UI-only tracking. - Keybindings (Ctrl+Enter / Ctrl+Shift+Enter) emit `run_triggered` (source `keybinding`). - Menus (menubar + legacy menu buttons) emit `run_triggered` (source `menu`). - Mixpanel provider now supports `trackRunTriggered` and forwards `run_triggered`. - `execution_start` tracking remains unchanged. Motivation GTM observed more `execution_start` events than `run_button_click`. This change clarifies attribution by adding a unified event across all triggers while preserving the UI-only `run_button_click` metric. Files - src/platform/telemetry/types.ts: Add `RunTriggeredMetadata`, `RUN_TRIGGERED`, provider method signature. - src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts: Implement `trackRunTriggered`. - src/components/actionbar/ComfyRunButton/ComfyQueueButton.vue: Emit `run_triggered` on button path. - src/services/keybindingService.ts: Emit `run_triggered` when queue commands are invoked via keybindings. - src/stores/menuItemStore.ts: Emit `run_triggered` for queue commands invoked via menubar. - src/scripts/ui.ts: Emit `run_triggered` for legacy menu queue buttons. Notes - `run_button_click` continues to represent UI button presses only. - `run_triggered` now represents all user-initiated runs with clear source attribution. QA - Cloud build: verify `app:run_triggered` appears with the correct `trigger_source` for button, keybinding, and menu triggers. - Verify `app:run_button_click` only fires for the button path. - Confirm `execution_start` still tracks as before. If preferred, we can extend `run_triggered` with additional fields (e.g., queue mode, batchCount) in a follow-up. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6499-feat-telemetry-add-unified-run_triggered-event-for-all-run-initiations-29e6d73d3650819fb481d3e0e925c50f) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action --- .../providers/cloud/MixpanelTelemetryProvider.ts | 8 ++++++++ src/platform/telemetry/types.ts | 4 ++++ src/scripts/ui.ts | 16 ++++++++++++++-- src/services/keybindingService.ts | 10 ++++++++++ src/stores/menuItemStore.ts | 14 +++++++++++++- 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts b/src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts index a66923501..20cff7d57 100644 --- a/src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts +++ b/src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts @@ -185,6 +185,14 @@ export class MixpanelTelemetryProvider implements TelemetryProvider { this.trackEvent(TelemetryEvents.RUN_BUTTON_CLICKED, runButtonProperties) } + trackRunTriggeredViaKeybinding(): void { + this.trackEvent(TelemetryEvents.RUN_TRIGGERED_KEYBINDING) + } + + trackRunTriggeredViaMenu(): void { + this.trackEvent(TelemetryEvents.RUN_TRIGGERED_MENU) + } + trackSurvey( stage: 'opened' | 'submitted', responses?: SurveyResponses diff --git a/src/platform/telemetry/types.ts b/src/platform/telemetry/types.ts index fd9225c2c..b20a265d2 100644 --- a/src/platform/telemetry/types.ts +++ b/src/platform/telemetry/types.ts @@ -206,6 +206,8 @@ export interface TelemetryProvider { trackAddApiCreditButtonClicked(): void trackApiCreditTopupButtonPurchaseClicked(amount: number): void trackRunButton(options?: { subscribe_to_run?: boolean }): void + trackRunTriggeredViaKeybinding(): void + trackRunTriggeredViaMenu(): void // Survey flow events trackSurvey(stage: 'opened' | 'submitted', responses?: SurveyResponses): void @@ -255,6 +257,8 @@ export const TelemetryEvents = { // Subscription Flow RUN_BUTTON_CLICKED: 'app:run_button_click', + RUN_TRIGGERED_KEYBINDING: 'app:run_triggered_keybinding', + RUN_TRIGGERED_MENU: 'app:run_triggered_menu', SUBSCRIPTION_REQUIRED_MODAL_OPENED: 'app:subscription_required_modal_opened', SUBSCRIBE_NOW_BUTTON_CLICKED: 'app:subscribe_now_button_clicked', MONTHLY_SUBSCRIPTION_SUCCEEDED: 'app:monthly_subscription_succeeded', diff --git a/src/scripts/ui.ts b/src/scripts/ui.ts index d3300a3ab..b8c92b71f 100644 --- a/src/scripts/ui.ts +++ b/src/scripts/ui.ts @@ -2,6 +2,8 @@ import { useSettingStore } from '@/platform/settings/settingStore' import { WORKFLOW_ACCEPT_STRING } from '@/platform/workflow/core/types/formats' import { type StatusWsMessageStatus, type TaskItem } from '@/schemas/apiSchema' import { useDialogService } from '@/services/dialogService' +import { isCloud } from '@/platform/distribution/types' +import { useTelemetry } from '@/platform/telemetry' import { useLitegraphService } from '@/services/litegraphService' import { useCommandStore } from '@/stores/commandStore' import { useWorkspaceStore } from '@/stores/workspaceStore' @@ -470,7 +472,12 @@ export class ComfyUI { $el('button.comfy-queue-btn', { id: 'queue-button', textContent: 'Queue Prompt', - onclick: () => app.queuePrompt(0, this.batchCount) + onclick: () => { + if (isCloud) { + useTelemetry()?.trackRunTriggeredViaMenu() + } + app.queuePrompt(0, this.batchCount) + } }), $el('div', {}, [ $el('label', { innerHTML: 'Extra options' }, [ @@ -572,7 +579,12 @@ export class ComfyUI { $el('button', { id: 'queue-front-button', textContent: 'Queue Front', - onclick: () => app.queuePrompt(-1, this.batchCount) + onclick: () => { + if (isCloud) { + useTelemetry()?.trackRunTriggeredViaMenu() + } + app.queuePrompt(-1, this.batchCount) + } }), $el('button', { $: (b) => (this.queue.button = b as HTMLButtonElement), diff --git a/src/services/keybindingService.ts b/src/services/keybindingService.ts index ed5049246..fff58fa57 100644 --- a/src/services/keybindingService.ts +++ b/src/services/keybindingService.ts @@ -1,5 +1,7 @@ import { CORE_KEYBINDINGS } from '@/constants/coreKeybindings' +import { isCloud } from '@/platform/distribution/types' import { useSettingStore } from '@/platform/settings/settingStore' +import { useTelemetry } from '@/platform/telemetry' import { app } from '@/scripts/app' import { useCommandStore } from '@/stores/commandStore' import { useDialogStore } from '@/stores/dialogStore' @@ -64,6 +66,14 @@ export const useKeybindingService = () => { // Prevent default browser behavior first, then execute the command event.preventDefault() + if ( + isCloud && + (keybinding.commandId === 'Comfy.QueuePrompt' || + keybinding.commandId === 'Comfy.QueuePromptFront' || + keybinding.commandId === 'Comfy.QueueSelectedOutputNodes') + ) { + useTelemetry()?.trackRunTriggeredViaKeybinding() + } await commandStore.execute(keybinding.commandId) return } diff --git a/src/stores/menuItemStore.ts b/src/stores/menuItemStore.ts index 0a24769a1..242e4641c 100644 --- a/src/stores/menuItemStore.ts +++ b/src/stores/menuItemStore.ts @@ -3,6 +3,8 @@ import type { MenuItem } from 'primevue/menuitem' import { ref } from 'vue' import { CORE_MENU_COMMANDS } from '@/constants/coreMenuCommands' +import { isCloud } from '@/platform/distribution/types' +import { useTelemetry } from '@/platform/telemetry' import type { ComfyExtension } from '@/types/comfy' import { useCommandStore } from './commandStore' @@ -62,7 +64,17 @@ export const useMenuItemStore = defineStore('menuItem', () => { .map( (command) => ({ - command: () => commandStore.execute(command.id), + command: () => { + if ( + isCloud && + (command.id === 'Comfy.QueuePrompt' || + command.id === 'Comfy.QueuePromptFront' || + command.id === 'Comfy.QueueSelectedOutputNodes') + ) { + useTelemetry()?.trackRunTriggeredViaMenu() + } + return commandStore.execute(command.id) + }, label: command.menubarLabel, icon: command.icon, tooltip: command.tooltip,