Skip to content

Commit a537124

Browse files
authored
feat: add telemetry to answer for user failed to find template (#6489)
## Summary Adds mixpanel telemetry with goal of: "We currently only know when a user opens a template workflow. But we also want to know if they failed to find what they want" Example mixpanel query: ``` app:template_library_closed WHERE template_selected = false AND time_spent_seconds >= 10 ``` But can drill down further into what filters were selected etc to answer what they were looking for but couldn't find. ``` 1. Event: app:template_filter_changed 2. Filter: - Add formula: "Where user also triggered app:template_library_closed with template_selected = false in same session" 3. Breakdown by: search_query 4. Sort by: Total Count (descending) Search Query Failed Sessions ----------------------------------- "flux video" 45 times "sdxl controlnet" 32 times "upscaler" 28 times (empty/just filter) 20 times ``` ``` Event: app:template_filter_changed WHERE filtered_count = 0 AND user did app:template_library_closed with template_selected = false Breakdown by: search_query ``` etc. https://www.notion.so/comfy-org/Number-of-users-who-open-the-template-library-and-where-do-they-click-29b6d73d36508044a595c0fb653ca6dc?source=copy_link ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6489-feat-add-telemetry-to-answer-for-user-failed-to-find-template-29d6d73d365081cdad72fd7c6ada5dc7) by [Unito](https://www.unito.io)
1 parent e05e988 commit a537124

File tree

6 files changed

+51
-8
lines changed

6 files changed

+51
-8
lines changed

src/components/custom/widget/WorkflowTemplateSelectorDialog.vue

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@
382382
<script setup lang="ts">
383383
import { useAsyncState } from '@vueuse/core'
384384
import ProgressSpinner from 'primevue/progressspinner'
385-
import { computed, onBeforeUnmount, provide, ref, watch } from 'vue'
385+
import { computed, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue'
386386
import { useI18n } from 'vue-i18n'
387387
388388
import IconButton from '@/components/button/IconButton.vue'
@@ -403,6 +403,8 @@ import LeftSidePanel from '@/components/widget/panel/LeftSidePanel.vue'
403403
import { useIntersectionObserver } from '@/composables/useIntersectionObserver'
404404
import { useLazyPagination } from '@/composables/useLazyPagination'
405405
import { useTemplateFiltering } from '@/composables/useTemplateFiltering'
406+
import { isCloud } from '@/platform/distribution/types'
407+
import { useTelemetry } from '@/platform/telemetry'
406408
import { useTemplateWorkflows } from '@/platform/workflow/templates/composables/useTemplateWorkflows'
407409
import { useWorkflowTemplatesStore } from '@/platform/workflow/templates/repositories/workflowTemplatesStore'
408410
import type { TemplateInfo } from '@/platform/workflow/templates/types/template'
@@ -412,10 +414,34 @@ import { createGridStyle } from '@/utils/gridUtil'
412414
413415
const { t } = useI18n()
414416
415-
const { onClose } = defineProps<{
417+
const { onClose: originalOnClose } = defineProps<{
416418
onClose: () => void
417419
}>()
418420
421+
// Track session time for telemetry
422+
const sessionStartTime = ref<number>(0)
423+
const templateWasSelected = ref(false)
424+
425+
onMounted(() => {
426+
sessionStartTime.value = Date.now()
427+
})
428+
429+
// Wrap onClose to track session end
430+
const onClose = () => {
431+
if (isCloud) {
432+
const timeSpentSeconds = Math.floor(
433+
(Date.now() - sessionStartTime.value) / 1000
434+
)
435+
436+
useTelemetry()?.trackTemplateLibraryClosed({
437+
template_selected: templateWasSelected.value,
438+
time_spent_seconds: timeSpentSeconds
439+
})
440+
}
441+
442+
originalOnClose()
443+
}
444+
419445
provide(OnCloseKey, onClose)
420446
421447
// Workflow templates store and composable
@@ -700,6 +726,7 @@ const onLoadWorkflow = async (template: any) => {
700726
template.name,
701727
getEffectiveSourceModule(template)
702728
)
729+
templateWasSelected.value = true
703730
onClose()
704731
} finally {
705732
loadingTemplate.value = null

src/components/sidebar/ComfyMenuButton.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import { useI18n } from 'vue-i18n'
7676
7777
import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.vue'
7878
import ComfyLogoTransparent from '@/components/icons/ComfyLogoTransparent.vue'
79+
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
7980
import SettingDialogContent from '@/platform/settings/components/SettingDialogContent.vue'
8081
import { useColorPaletteService } from '@/services/colorPaletteService'
8182
import { useCommandStore } from '@/stores/commandStore'
@@ -160,7 +161,7 @@ const extraMenuItems = computed(() => [
160161
key: 'browse-templates',
161162
label: t('menuLabels.Browse Templates'),
162163
icon: 'icon-[comfy--template]',
163-
command: () => commandStore.execute('Comfy.BrowseTemplates')
164+
command: () => useWorkflowTemplateSelectorDialog().show('menu')
164165
},
165166
{
166167
key: 'settings',

src/components/sidebar/SidebarTemplatesButton.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,18 @@
1212
<script setup lang="ts">
1313
import { computed } from 'vue'
1414
15+
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
1516
import { useSettingStore } from '@/platform/settings/settingStore'
16-
import { useCommandStore } from '@/stores/commandStore'
1717
1818
import SidebarIcon from './SidebarIcon.vue'
1919
2020
const settingStore = useSettingStore()
21-
const commandStore = useCommandStore()
2221
2322
const isSmall = computed(
2423
() => settingStore.get('Comfy.Sidebar.Size') === 'small'
2524
)
2625
2726
const openTemplates = () => {
28-
void commandStore.execute('Comfy.BrowseTemplates')
27+
useWorkflowTemplateSelectorDialog().show('sidebar')
2928
}
3029
</script>

src/composables/useWorkflowTemplateSelectorDialog.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export const useWorkflowTemplateSelectorDialog = () => {
1313
dialogStore.closeDialog({ key: DIALOG_KEY })
1414
}
1515

16-
function show() {
17-
useTelemetry()?.trackTemplateLibraryOpened({ source: 'command' })
16+
function show(source: 'sidebar' | 'menu' | 'command' = 'command') {
17+
useTelemetry()?.trackTemplateLibraryOpened({ source })
1818

1919
dialogService.showLayoutDialog({
2020
key: DIALOG_KEY,

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
TelemetryProvider,
2727
TemplateFilterMetadata,
2828
TemplateLibraryMetadata,
29+
TemplateLibraryClosedMetadata,
2930
TemplateMetadata,
3031
WorkflowImportMetadata
3132
} from '../../types'
@@ -235,6 +236,10 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
235236
this.trackEvent(TelemetryEvents.TEMPLATE_LIBRARY_OPENED, metadata)
236237
}
237238

239+
trackTemplateLibraryClosed(metadata: TemplateLibraryClosedMetadata): void {
240+
this.trackEvent(TelemetryEvents.TEMPLATE_LIBRARY_CLOSED, metadata)
241+
}
242+
238243
trackWorkflowImported(metadata: WorkflowImportMetadata): void {
239244
this.trackEvent(TelemetryEvents.WORKFLOW_IMPORTED, metadata)
240245
}

src/platform/telemetry/types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ export interface TemplateLibraryMetadata {
122122
source: 'sidebar' | 'menu' | 'command'
123123
}
124124

125+
/**
126+
* Template library closed metadata
127+
*/
128+
export interface TemplateLibraryClosedMetadata {
129+
template_selected: boolean
130+
time_spent_seconds: number
131+
}
132+
125133
/**
126134
* Page visibility metadata
127135
*/
@@ -193,6 +201,7 @@ export interface TelemetryProvider {
193201
// Template workflow events
194202
trackTemplate(metadata: TemplateMetadata): void
195203
trackTemplateLibraryOpened(metadata: TemplateLibraryMetadata): void
204+
trackTemplateLibraryClosed(metadata: TemplateLibraryClosedMetadata): void
196205

197206
// Workflow management events
198207
trackWorkflowImported(metadata: WorkflowImportMetadata): void
@@ -249,6 +258,7 @@ export const TelemetryEvents = {
249258
// Template Tracking
250259
TEMPLATE_WORKFLOW_OPENED: 'app:template_workflow_opened',
251260
TEMPLATE_LIBRARY_OPENED: 'app:template_library_opened',
261+
TEMPLATE_LIBRARY_CLOSED: 'app:template_library_closed',
252262

253263
// Workflow Management
254264
WORKFLOW_IMPORTED: 'app:workflow_imported',
@@ -289,6 +299,7 @@ export type TelemetryEventProperties =
289299
| CreditTopupMetadata
290300
| WorkflowImportMetadata
291301
| TemplateLibraryMetadata
302+
| TemplateLibraryClosedMetadata
292303
| PageVisibilityMetadata
293304
| TabCountMetadata
294305
| NodeSearchMetadata

0 commit comments

Comments
 (0)