From b96fbbd55e19a1e7ab131595ff3bca03d0139354 Mon Sep 17 00:00:00 2001 From: ricardo Date: Thu, 10 Aug 2023 22:47:01 -0400 Subject: [PATCH 1/9] Remove PostHog event calls --- packages/editor-ui/src/plugins/telemetry/index.ts | 15 +++++++++++---- packages/editor-ui/src/stores/posthog.store.ts | 12 ++++++++---- packages/editor-ui/src/stores/telemetry.store.ts | 10 +++++++--- .../src/views/TemplatesCollectionView.vue | 2 +- .../editor-ui/src/views/TemplatesWorkflowView.vue | 2 +- packages/workflow/src/Interfaces.ts | 2 ++ 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/editor-ui/src/plugins/telemetry/index.ts b/packages/editor-ui/src/plugins/telemetry/index.ts index 295ea7a0061dd..1d8407092deac 100644 --- a/packages/editor-ui/src/plugins/telemetry/index.ts +++ b/packages/editor-ui/src/plugins/telemetry/index.ts @@ -1,5 +1,10 @@ import type { Plugin } from 'vue'; -import type { ITelemetrySettings, ITelemetryTrackProperties, IDataObject } from 'n8n-workflow'; +import type { + ITelemetrySettings, + ITelemetryTrackProperties, + IDataObject, + Integrations, +} from 'n8n-workflow'; import type { RouteLocation } from 'vue-router'; import type { INodeCreateElement, IUpdateInformation } from '@/Interface'; @@ -79,7 +84,7 @@ export class Telemetry { } } - track(event: string, properties?: ITelemetryTrackProperties) { + track(event: string, properties?: ITelemetryTrackProperties, integrations: Integrations = {}) { if (!this.rudderStack) return; const updatedProperties = { @@ -87,7 +92,9 @@ export class Telemetry { version_cli: useRootStore().versionCli, }; - this.rudderStack.track(event, updatedProperties); + this.rudderStack.track(event, updatedProperties, { + integrations: { PostHog: false, ...integrations }, + }); } page(route: Route) { @@ -187,7 +194,7 @@ export class Telemetry { this.track('User viewed node category', properties); break; case 'nodeView.addNodeButton': - this.track('User added node to workflow canvas', properties); + this.track('User added node to workflow canvas', properties, { PostHog: true }); break; case 'nodeView.addSticky': this.track('User inserted workflow note', properties); diff --git a/packages/editor-ui/src/stores/posthog.store.ts b/packages/editor-ui/src/stores/posthog.store.ts index 5bc219f0f1edf..b8793eeac2b65 100644 --- a/packages/editor-ui/src/stores/posthog.store.ts +++ b/packages/editor-ui/src/stores/posthog.store.ts @@ -153,10 +153,14 @@ export const usePostHog = defineStore('posthog', () => { return; } - telemetryStore.track(EVENTS.IS_PART_OF_EXPERIMENT, { - name, - variant, - }); + telemetryStore.track( + EVENTS.IS_PART_OF_EXPERIMENT, + { + name, + variant, + }, + { PostHog: true }, + ); trackedDemoExp.value[name] = variant; }; diff --git a/packages/editor-ui/src/stores/telemetry.store.ts b/packages/editor-ui/src/stores/telemetry.store.ts index ed3b68bbf01f4..9f67e2e523456 100644 --- a/packages/editor-ui/src/stores/telemetry.store.ts +++ b/packages/editor-ui/src/stores/telemetry.store.ts @@ -1,5 +1,5 @@ import type { Telemetry } from '@/plugins/telemetry'; -import type { ITelemetryTrackProperties } from 'n8n-workflow'; +import type { ITelemetryTrackProperties, Integrations } from 'n8n-workflow'; import { defineStore } from 'pinia'; import type { Ref } from 'vue'; import { ref } from 'vue'; @@ -11,8 +11,12 @@ export const useTelemetryStore = defineStore('telemetry', () => { telemetry.value = tel; }; - const track = (event: string, properties?: ITelemetryTrackProperties) => { - telemetry.value?.track(event, properties); + const track = ( + event: string, + properties?: ITelemetryTrackProperties, + integrations: Integrations = {}, + ) => { + telemetry.value?.track(event, properties, integrations); }; return { diff --git a/packages/editor-ui/src/views/TemplatesCollectionView.vue b/packages/editor-ui/src/views/TemplatesCollectionView.vue index 45acfe26260de..50a33d0369c5c 100644 --- a/packages/editor-ui/src/views/TemplatesCollectionView.vue +++ b/packages/editor-ui/src/views/TemplatesCollectionView.vue @@ -122,7 +122,7 @@ export default defineComponent({ source: 'collection', }; void this.$externalHooks().run('templatesCollectionView.onUseWorkflow', telemetryPayload); - this.$telemetry.track('User inserted workflow template', telemetryPayload); + this.$telemetry.track('User inserted workflow template', telemetryPayload, { PostHog: true }); this.navigateTo(event, VIEWS.TEMPLATE_IMPORT, id); }, diff --git a/packages/editor-ui/src/views/TemplatesWorkflowView.vue b/packages/editor-ui/src/views/TemplatesWorkflowView.vue index cb45aa60e720b..978aedc446c9c 100644 --- a/packages/editor-ui/src/views/TemplatesWorkflowView.vue +++ b/packages/editor-ui/src/views/TemplatesWorkflowView.vue @@ -101,7 +101,7 @@ export default defineComponent({ }; void this.$externalHooks().run('templatesWorkflowView.openWorkflow', telemetryPayload); - this.$telemetry.track('User inserted workflow template', telemetryPayload); + this.$telemetry.track('User inserted workflow template', telemetryPayload, { PostHog: true }); if (e.metaKey || e.ctrlKey) { const route = this.$router.resolve({ name: VIEWS.TEMPLATE_IMPORT, params: { id } }); diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index c5cec473a257d..17377e3a1d2f9 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -1889,6 +1889,8 @@ export interface ITelemetryTrackProperties { [key: string]: GenericValue; } +export type Integrations = Record<'PostHog', boolean> | {}; + export interface INodesGraph { node_types: string[]; node_connections: IDataObject[]; From 9868feaa9e47ecfef18af447764fdc2e63bea64b Mon Sep 17 00:00:00 2001 From: ricardo Date: Fri, 11 Aug 2023 10:45:21 -0400 Subject: [PATCH 2/9] Stop sending BE telemetry events to Posthog --- packages/cli/src/InternalHooks.ts | 43 +++++++++++------------------ packages/cli/src/telemetry/index.ts | 14 ++++------ 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/packages/cli/src/InternalHooks.ts b/packages/cli/src/InternalHooks.ts index 0a0b636998793..ebd3bc2570d86 100644 --- a/packages/cli/src/InternalHooks.ts +++ b/packages/cli/src/InternalHooks.ts @@ -124,7 +124,6 @@ export class InternalHooks implements IInternalHooksClass { return this.telemetry.track( 'User responded to personalization questions', personalizationSurveyData, - { withPostHog: true }, ); } @@ -190,21 +189,17 @@ export class InternalHooks implements IInternalHooksClass { workflowName: workflow.name, }, }), - this.telemetry.track( - 'User saved workflow', - { - user_id: user.id, - workflow_id: workflow.id, - node_graph_string: JSON.stringify(nodeGraph), - notes_count_overlapping: overlappingCount, - notes_count_non_overlapping: notesCount - overlappingCount, - version_cli: N8N_VERSION, - num_tags: workflow.tags?.length ?? 0, - public_api: publicApi, - sharing_role: userRole, - }, - { withPostHog: true }, - ), + this.telemetry.track('User saved workflow', { + user_id: user.id, + workflow_id: workflow.id, + node_graph_string: JSON.stringify(nodeGraph), + notes_count_overlapping: overlappingCount, + notes_count_non_overlapping: notesCount - overlappingCount, + version_cli: N8N_VERSION, + num_tags: workflow.tags?.length ?? 0, + public_api: publicApi, + sharing_role: userRole, + }), ]); } @@ -415,11 +410,7 @@ export class InternalHooks implements IInternalHooksClass { node_id: nodeGraphResult.nameIndices[runData.data.startData?.destinationNode], }; - promises.push( - this.telemetry.track('Manual node exec finished', telemetryPayload, { - withPostHog: true, - }), - ); + promises.push(this.telemetry.track('Manual node exec finished', telemetryPayload)); } else { nodeGraphResult.webhookNodeNames.forEach((name: string) => { const execJson = runData.data.resultData.runData[name]?.[0]?.data?.main?.[0]?.[0] @@ -432,9 +423,7 @@ export class InternalHooks implements IInternalHooksClass { }); promises.push( - this.telemetry.track('Manual workflow exec finished', manualExecEventProperties, { - withPostHog: true, - }), + this.telemetry.track('Manual workflow exec finished', manualExecEventProperties), ); } } @@ -484,7 +473,7 @@ export class InternalHooks implements IInternalHooksClass { user_id_list: userList, }; - return this.telemetry.track('User updated workflow sharing', properties, { withPostHog: true }); + return this.telemetry.track('User updated workflow sharing', properties); } async onN8nStop(): Promise { @@ -1017,7 +1006,7 @@ export class InternalHooks implements IInternalHooksClass { user_id: string; workflow_id: string; }): Promise { - return this.telemetry.track('Workflow first prod success', data, { withPostHog: true }); + return this.telemetry.track('Workflow first prod success', data); } async onFirstWorkflowDataLoad(data: { @@ -1028,7 +1017,7 @@ export class InternalHooks implements IInternalHooksClass { credential_type?: string; credential_id?: string; }): Promise { - return this.telemetry.track('Workflow first data fetched', data, { withPostHog: true }); + return this.telemetry.track('Workflow first data fetched', data); } /** diff --git a/packages/cli/src/telemetry/index.ts b/packages/cli/src/telemetry/index.ts index 7e78ca996a5b5..75b87a2c6b801 100644 --- a/packages/cli/src/telemetry/index.ts +++ b/packages/cli/src/telemetry/index.ts @@ -95,15 +95,11 @@ export class Telemetry { return sum > 0; }) .map(async (workflowId) => { - const promise = this.track( - 'Workflow execution count', - { - event_version: '2', - workflow_id: workflowId, - ...this.executionCountsBuffer[workflowId], - }, - { withPostHog: true }, - ); + const promise = this.track('Workflow execution count', { + event_version: '2', + workflow_id: workflowId, + ...this.executionCountsBuffer[workflowId], + }); return promise; }); From d7906cca6a0787e560a29e956eee775d81807447 Mon Sep 17 00:00:00 2001 From: ricardo Date: Thu, 10 Aug 2023 22:47:01 -0400 Subject: [PATCH 3/9] Revert "Remove PostHog event calls" This reverts commit b96fbbd55e19a1e7ab131595ff3bca03d0139354. --- packages/editor-ui/src/plugins/telemetry/index.ts | 15 ++++----------- packages/editor-ui/src/stores/posthog.store.ts | 12 ++++-------- packages/editor-ui/src/stores/telemetry.store.ts | 10 +++------- .../src/views/TemplatesCollectionView.vue | 2 +- .../editor-ui/src/views/TemplatesWorkflowView.vue | 2 +- packages/workflow/src/Interfaces.ts | 2 -- 6 files changed, 13 insertions(+), 30 deletions(-) diff --git a/packages/editor-ui/src/plugins/telemetry/index.ts b/packages/editor-ui/src/plugins/telemetry/index.ts index 1d8407092deac..295ea7a0061dd 100644 --- a/packages/editor-ui/src/plugins/telemetry/index.ts +++ b/packages/editor-ui/src/plugins/telemetry/index.ts @@ -1,10 +1,5 @@ import type { Plugin } from 'vue'; -import type { - ITelemetrySettings, - ITelemetryTrackProperties, - IDataObject, - Integrations, -} from 'n8n-workflow'; +import type { ITelemetrySettings, ITelemetryTrackProperties, IDataObject } from 'n8n-workflow'; import type { RouteLocation } from 'vue-router'; import type { INodeCreateElement, IUpdateInformation } from '@/Interface'; @@ -84,7 +79,7 @@ export class Telemetry { } } - track(event: string, properties?: ITelemetryTrackProperties, integrations: Integrations = {}) { + track(event: string, properties?: ITelemetryTrackProperties) { if (!this.rudderStack) return; const updatedProperties = { @@ -92,9 +87,7 @@ export class Telemetry { version_cli: useRootStore().versionCli, }; - this.rudderStack.track(event, updatedProperties, { - integrations: { PostHog: false, ...integrations }, - }); + this.rudderStack.track(event, updatedProperties); } page(route: Route) { @@ -194,7 +187,7 @@ export class Telemetry { this.track('User viewed node category', properties); break; case 'nodeView.addNodeButton': - this.track('User added node to workflow canvas', properties, { PostHog: true }); + this.track('User added node to workflow canvas', properties); break; case 'nodeView.addSticky': this.track('User inserted workflow note', properties); diff --git a/packages/editor-ui/src/stores/posthog.store.ts b/packages/editor-ui/src/stores/posthog.store.ts index b8793eeac2b65..5bc219f0f1edf 100644 --- a/packages/editor-ui/src/stores/posthog.store.ts +++ b/packages/editor-ui/src/stores/posthog.store.ts @@ -153,14 +153,10 @@ export const usePostHog = defineStore('posthog', () => { return; } - telemetryStore.track( - EVENTS.IS_PART_OF_EXPERIMENT, - { - name, - variant, - }, - { PostHog: true }, - ); + telemetryStore.track(EVENTS.IS_PART_OF_EXPERIMENT, { + name, + variant, + }); trackedDemoExp.value[name] = variant; }; diff --git a/packages/editor-ui/src/stores/telemetry.store.ts b/packages/editor-ui/src/stores/telemetry.store.ts index 9f67e2e523456..ed3b68bbf01f4 100644 --- a/packages/editor-ui/src/stores/telemetry.store.ts +++ b/packages/editor-ui/src/stores/telemetry.store.ts @@ -1,5 +1,5 @@ import type { Telemetry } from '@/plugins/telemetry'; -import type { ITelemetryTrackProperties, Integrations } from 'n8n-workflow'; +import type { ITelemetryTrackProperties } from 'n8n-workflow'; import { defineStore } from 'pinia'; import type { Ref } from 'vue'; import { ref } from 'vue'; @@ -11,12 +11,8 @@ export const useTelemetryStore = defineStore('telemetry', () => { telemetry.value = tel; }; - const track = ( - event: string, - properties?: ITelemetryTrackProperties, - integrations: Integrations = {}, - ) => { - telemetry.value?.track(event, properties, integrations); + const track = (event: string, properties?: ITelemetryTrackProperties) => { + telemetry.value?.track(event, properties); }; return { diff --git a/packages/editor-ui/src/views/TemplatesCollectionView.vue b/packages/editor-ui/src/views/TemplatesCollectionView.vue index 50a33d0369c5c..45acfe26260de 100644 --- a/packages/editor-ui/src/views/TemplatesCollectionView.vue +++ b/packages/editor-ui/src/views/TemplatesCollectionView.vue @@ -122,7 +122,7 @@ export default defineComponent({ source: 'collection', }; void this.$externalHooks().run('templatesCollectionView.onUseWorkflow', telemetryPayload); - this.$telemetry.track('User inserted workflow template', telemetryPayload, { PostHog: true }); + this.$telemetry.track('User inserted workflow template', telemetryPayload); this.navigateTo(event, VIEWS.TEMPLATE_IMPORT, id); }, diff --git a/packages/editor-ui/src/views/TemplatesWorkflowView.vue b/packages/editor-ui/src/views/TemplatesWorkflowView.vue index 978aedc446c9c..cb45aa60e720b 100644 --- a/packages/editor-ui/src/views/TemplatesWorkflowView.vue +++ b/packages/editor-ui/src/views/TemplatesWorkflowView.vue @@ -101,7 +101,7 @@ export default defineComponent({ }; void this.$externalHooks().run('templatesWorkflowView.openWorkflow', telemetryPayload); - this.$telemetry.track('User inserted workflow template', telemetryPayload, { PostHog: true }); + this.$telemetry.track('User inserted workflow template', telemetryPayload); if (e.metaKey || e.ctrlKey) { const route = this.$router.resolve({ name: VIEWS.TEMPLATE_IMPORT, params: { id } }); diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 17377e3a1d2f9..c5cec473a257d 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -1889,8 +1889,6 @@ export interface ITelemetryTrackProperties { [key: string]: GenericValue; } -export type Integrations = Record<'PostHog', boolean> | {}; - export interface INodesGraph { node_types: string[]; node_connections: IDataObject[]; From ac355ad3b5d756b56e9a0c59d67f6ccdcc03aaab Mon Sep 17 00:00:00 2001 From: ricardo Date: Fri, 11 Aug 2023 11:03:42 -0400 Subject: [PATCH 4/9] Explicitly send events to posthog --- packages/editor-ui/src/Interface.ts | 1 + packages/editor-ui/src/plugins/telemetry/index.ts | 2 ++ packages/editor-ui/src/stores/posthog.store.ts | 9 ++++++++- packages/editor-ui/src/views/TemplatesCollectionView.vue | 4 +++- packages/editor-ui/src/views/TemplatesWorkflowView.vue | 4 +++- 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index d38bef1f124bc..f7ab5ed80ca45 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -78,6 +78,7 @@ declare global { reset?(resetDeviceId?: boolean): void; onFeatureFlags?(callback: (keys: string[], map: FeatureFlags) => void): void; reloadFeatureFlags?(): void; + capture?(event: string, properties: IDataObject): void; }; analytics?: { track(event: string, proeprties?: ITelemetryTrackProperties): void; diff --git a/packages/editor-ui/src/plugins/telemetry/index.ts b/packages/editor-ui/src/plugins/telemetry/index.ts index 295ea7a0061dd..e0cb7b76e484c 100644 --- a/packages/editor-ui/src/plugins/telemetry/index.ts +++ b/packages/editor-ui/src/plugins/telemetry/index.ts @@ -8,6 +8,7 @@ import { useSettingsStore } from '@/stores/settings.store'; import { useRootStore } from '@/stores/n8nRoot.store'; import { useTelemetryStore } from '@/stores/telemetry.store'; import { SLACK_NODE_TYPE } from '@/constants'; +import { usePostHog } from '@/stores/posthog.store'; export class Telemetry { private pageEventQueue: Array<{ route: RouteLocation }>; @@ -188,6 +189,7 @@ export class Telemetry { break; case 'nodeView.addNodeButton': this.track('User added node to workflow canvas', properties); + usePostHog().capture('User added node to workflow canvas', properties); break; case 'nodeView.addSticky': this.track('User inserted workflow note', properties); diff --git a/packages/editor-ui/src/stores/posthog.store.ts b/packages/editor-ui/src/stores/posthog.store.ts index 5bc219f0f1edf..50f90ae91df19 100644 --- a/packages/editor-ui/src/stores/posthog.store.ts +++ b/packages/editor-ui/src/stores/posthog.store.ts @@ -4,7 +4,7 @@ import { defineStore } from 'pinia'; import { useUsersStore } from '@/stores/users.store'; import { useRootStore } from '@/stores/n8nRoot.store'; import { useSettingsStore } from '@/stores/settings.store'; -import type { FeatureFlags } from 'n8n-workflow'; +import type { FeatureFlags, IDataObject } from 'n8n-workflow'; import { EXPERIMENTS_TO_TRACK, LOCAL_STORAGE_EXPERIMENT_OVERRIDES } from '@/constants'; import { useTelemetryStore } from './telemetry.store'; import { debounce } from 'lodash-es'; @@ -161,10 +161,17 @@ export const usePostHog = defineStore('posthog', () => { trackedDemoExp.value[name] = variant; }; + const capture = (event: string, properties: IDataObject) => { + if (typeof window.posthog?.capture === 'function') { + window.posthog.capture(event, properties); + } + }; + return { init, isVariantEnabled, getVariant, reset, + capture, }; }); diff --git a/packages/editor-ui/src/views/TemplatesCollectionView.vue b/packages/editor-ui/src/views/TemplatesCollectionView.vue index 45acfe26260de..2ae9307ffcfb1 100644 --- a/packages/editor-ui/src/views/TemplatesCollectionView.vue +++ b/packages/editor-ui/src/views/TemplatesCollectionView.vue @@ -68,6 +68,7 @@ import type { import { setPageTitle } from '@/utils'; import { VIEWS } from '@/constants'; import { useTemplatesStore } from '@/stores/templates.store'; +import { usePostHog } from '@/stores/posthog.store'; export default defineComponent({ name: 'TemplatesCollectionView', @@ -78,7 +79,7 @@ export default defineComponent({ TemplatesView, }, computed: { - ...mapStores(useTemplatesStore), + ...mapStores(useTemplatesStore, usePostHog), collection(): null | ITemplatesCollectionFull { return this.templatesStore.getCollectionById(this.collectionId); }, @@ -123,6 +124,7 @@ export default defineComponent({ }; void this.$externalHooks().run('templatesCollectionView.onUseWorkflow', telemetryPayload); this.$telemetry.track('User inserted workflow template', telemetryPayload); + this.posthogStore.capture('User inserted workflow template', telemetryPayload); this.navigateTo(event, VIEWS.TEMPLATE_IMPORT, id); }, diff --git a/packages/editor-ui/src/views/TemplatesWorkflowView.vue b/packages/editor-ui/src/views/TemplatesWorkflowView.vue index cb45aa60e720b..03b8b17f4908b 100644 --- a/packages/editor-ui/src/views/TemplatesWorkflowView.vue +++ b/packages/editor-ui/src/views/TemplatesWorkflowView.vue @@ -67,6 +67,7 @@ import { workflowHelpers } from '@/mixins/workflowHelpers'; import { setPageTitle } from '@/utils'; import { VIEWS } from '@/constants'; import { useTemplatesStore } from '@/stores/templates.store'; +import { usePostHog } from '@/stores/posthog.store'; export default defineComponent({ name: 'TemplatesWorkflowView', @@ -77,7 +78,7 @@ export default defineComponent({ WorkflowPreview, }, computed: { - ...mapStores(useTemplatesStore), + ...mapStores(useTemplatesStore, usePostHog), template(): ITemplatesWorkflow | ITemplatesWorkflowFull { return this.templatesStore.getTemplateById(this.templateId); }, @@ -102,6 +103,7 @@ export default defineComponent({ void this.$externalHooks().run('templatesWorkflowView.openWorkflow', telemetryPayload); this.$telemetry.track('User inserted workflow template', telemetryPayload); + this.posthogStore.capture('User inserted workflow template', telemetryPayload); if (e.metaKey || e.ctrlKey) { const route = this.$router.resolve({ name: VIEWS.TEMPLATE_IMPORT, params: { id } }); From af4c99d3ad72e4920620b80d2b02ff05491a5714 Mon Sep 17 00:00:00 2001 From: ricardo Date: Fri, 11 Aug 2023 13:56:02 -0400 Subject: [PATCH 5/9] add withPostHog parameter to FE telemetry --- packages/editor-ui/src/plugins/telemetry/index.ts | 13 ++++++++++--- .../editor-ui/src/views/TemplatesCollectionView.vue | 6 +++--- .../editor-ui/src/views/TemplatesWorkflowView.vue | 6 +++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/editor-ui/src/plugins/telemetry/index.ts b/packages/editor-ui/src/plugins/telemetry/index.ts index e0cb7b76e484c..0ebe7ffa95fae 100644 --- a/packages/editor-ui/src/plugins/telemetry/index.ts +++ b/packages/editor-ui/src/plugins/telemetry/index.ts @@ -80,7 +80,11 @@ export class Telemetry { } } - track(event: string, properties?: ITelemetryTrackProperties) { + track( + event: string, + properties?: ITelemetryTrackProperties, + { withPostHog } = { withPostHog: false }, + ) { if (!this.rudderStack) return; const updatedProperties = { @@ -89,6 +93,10 @@ export class Telemetry { }; this.rudderStack.track(event, updatedProperties); + + if (withPostHog) { + usePostHog().capture(event, updatedProperties); + } } page(route: Route) { @@ -188,8 +196,7 @@ export class Telemetry { this.track('User viewed node category', properties); break; case 'nodeView.addNodeButton': - this.track('User added node to workflow canvas', properties); - usePostHog().capture('User added node to workflow canvas', properties); + this.track('User added node to workflow canvas', properties, { withPostHog: true }); break; case 'nodeView.addSticky': this.track('User inserted workflow note', properties); diff --git a/packages/editor-ui/src/views/TemplatesCollectionView.vue b/packages/editor-ui/src/views/TemplatesCollectionView.vue index 2ae9307ffcfb1..ab2b617cfe942 100644 --- a/packages/editor-ui/src/views/TemplatesCollectionView.vue +++ b/packages/editor-ui/src/views/TemplatesCollectionView.vue @@ -123,9 +123,9 @@ export default defineComponent({ source: 'collection', }; void this.$externalHooks().run('templatesCollectionView.onUseWorkflow', telemetryPayload); - this.$telemetry.track('User inserted workflow template', telemetryPayload); - this.posthogStore.capture('User inserted workflow template', telemetryPayload); - + this.$telemetry.track('User inserted workflow template', telemetryPayload, { + withPostHog: true, + }); this.navigateTo(event, VIEWS.TEMPLATE_IMPORT, id); }, navigateTo(e: MouseEvent, page: string, id: string) { diff --git a/packages/editor-ui/src/views/TemplatesWorkflowView.vue b/packages/editor-ui/src/views/TemplatesWorkflowView.vue index 03b8b17f4908b..d2761f36e878b 100644 --- a/packages/editor-ui/src/views/TemplatesWorkflowView.vue +++ b/packages/editor-ui/src/views/TemplatesWorkflowView.vue @@ -102,9 +102,9 @@ export default defineComponent({ }; void this.$externalHooks().run('templatesWorkflowView.openWorkflow', telemetryPayload); - this.$telemetry.track('User inserted workflow template', telemetryPayload); - this.posthogStore.capture('User inserted workflow template', telemetryPayload); - + this.$telemetry.track('User inserted workflow template', telemetryPayload, { + withPostHog: true, + }); if (e.metaKey || e.ctrlKey) { const route = this.$router.resolve({ name: VIEWS.TEMPLATE_IMPORT, params: { id } }); window.open(route.href, '_blank'); From 728ca49bb0f523c79ae6ada850c88c21cdf18656 Mon Sep 17 00:00:00 2001 From: ricardo Date: Tue, 15 Aug 2023 15:55:59 -0400 Subject: [PATCH 6/9] Set PostHog metadata after sending personalization survey --- packages/editor-ui/src/Interface.ts | 4 ++++ .../src/components/PersonalizationModal.vue | 5 ++++- packages/editor-ui/src/stores/posthog.store.ts | 12 ++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index f7ab5ed80ca45..1cf1ba0c39715 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -79,6 +79,10 @@ declare global { onFeatureFlags?(callback: (keys: string[], map: FeatureFlags) => void): void; reloadFeatureFlags?(): void; capture?(event: string, properties: IDataObject): void; + register?(metadata: IDataObject): void; + people?: { + set?(metadata: IDataObject): void; + }; }; analytics?: { track(event: string, proeprties?: ITelemetryTrackProperties): void; diff --git a/packages/editor-ui/src/components/PersonalizationModal.vue b/packages/editor-ui/src/components/PersonalizationModal.vue index c47e40b3b728e..b3566d424c3d6 100644 --- a/packages/editor-ui/src/components/PersonalizationModal.vue +++ b/packages/editor-ui/src/components/PersonalizationModal.vue @@ -138,6 +138,7 @@ import { useSettingsStore } from '@/stores/settings.store'; import { useRootStore } from '@/stores/n8nRoot.store'; import { useUsersStore } from '@/stores/users.store'; import { createEventBus } from 'n8n-design-system/utils'; +import { usePostHog } from '@/stores'; export default defineComponent({ name: 'PersonalizationModal', @@ -166,7 +167,7 @@ export default defineComponent({ }; }, computed: { - ...mapStores(useRootStore, useSettingsStore, useUIStore, useUsersStore), + ...mapStores(useRootStore, useSettingsStore, useUIStore, useUsersStore, usePostHog), survey() { const survey: IFormInputs = [ { @@ -645,6 +646,8 @@ export default defineComponent({ await this.usersStore.submitPersonalizationSurvey(survey as IPersonalizationLatestVersion); + this.posthogStore.setMetadata(survey, 'user'); + if (Object.keys(values).length === 0) { this.closeDialog(); } diff --git a/packages/editor-ui/src/stores/posthog.store.ts b/packages/editor-ui/src/stores/posthog.store.ts index 50f90ae91df19..ffe95ed53a3ed 100644 --- a/packages/editor-ui/src/stores/posthog.store.ts +++ b/packages/editor-ui/src/stores/posthog.store.ts @@ -167,11 +167,23 @@ export const usePostHog = defineStore('posthog', () => { } }; + const setMetadata = (metadata: IDataObject, target: 'user' | 'events') => { + if (typeof window.posthog?.people?.set !== 'function') return; + if (typeof window.posthog?.register !== 'function') return; + + if (target === 'user') { + window.posthog?.people?.set(metadata); + } else if (target === 'events') { + window.posthog?.register(metadata); + } + }; + return { init, isVariantEnabled, getVariant, reset, capture, + setMetadata, }; }); From 4e3b8bdb1469366e1d36d20ef7741b9be44ccf55 Mon Sep 17 00:00:00 2001 From: ricardo Date: Tue, 15 Aug 2023 15:58:41 -0400 Subject: [PATCH 7/9] Stop injecting posthog-hooks as default --- packages/cli/src/config/schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/config/schema.ts b/packages/cli/src/config/schema.ts index 74e4ae67eff64..fceebe2a31c26 100644 --- a/packages/cli/src/config/schema.ts +++ b/packages/cli/src/config/schema.ts @@ -762,7 +762,7 @@ export const schema = { externalFrontendHooksUrls: { doc: 'URLs to external frontend hooks files, ; separated', format: String, - default: 'https://public.n8n.cloud/posthog-hooks.js', + default: '', env: 'EXTERNAL_FRONTEND_HOOKS_URLS', }, From f238964fc968ae0a19319b22ba29622c5989d493 Mon Sep 17 00:00:00 2001 From: ricardo Date: Tue, 15 Aug 2023 19:13:09 -0400 Subject: [PATCH 8/9] Improvements --- packages/cli/src/Server.ts | 2 +- packages/cli/src/controllers/owner.controller.ts | 9 ++++++++- packages/editor-ui/src/Interface.ts | 1 + packages/editor-ui/src/api/users.ts | 2 +- packages/editor-ui/src/stores/users.store.ts | 4 ++-- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 8104b2ea32353..b988cff30a66f 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -482,7 +482,7 @@ export class Server extends AbstractServer { const controllers: object[] = [ new EventBusController(), new AuthController({ config, internalHooks, repositories, logger, postHog }), - new OwnerController({ config, internalHooks, repositories, logger }), + new OwnerController({ config, internalHooks, repositories, logger, postHog }), new MeController({ externalHooks, internalHooks, repositories, logger }), new NodeTypesController({ config, nodeTypes }), new PasswordResetController({ diff --git a/packages/cli/src/controllers/owner.controller.ts b/packages/cli/src/controllers/owner.controller.ts index 4875e10ec3cca..c09b4c87a5e96 100644 --- a/packages/cli/src/controllers/owner.controller.ts +++ b/packages/cli/src/controllers/owner.controller.ts @@ -6,6 +6,7 @@ import { hashPassword, sanitizeUser, validatePassword, + withFeatureFlags, } from '@/UserManagement/UserManagementHelper'; import { issueCookie } from '@/auth/jwt'; import { Response } from 'express'; @@ -14,6 +15,7 @@ import type { Config } from '@/config'; import { OwnerRequest } from '@/requests'; import type { IDatabaseCollections, IInternalHooksClass } from '@/Interfaces'; import type { SettingsRepository, UserRepository } from '@db/repositories'; +import type { PostHogClient } from '@/posthog'; @Authorized(['global', 'owner']) @RestController('/owner') @@ -28,22 +30,27 @@ export class OwnerController { private readonly settingsRepository: SettingsRepository; + private readonly postHog?: PostHogClient; + constructor({ config, logger, internalHooks, repositories, + postHog, }: { config: Config; logger: ILogger; internalHooks: IInternalHooksClass; repositories: Pick; + postHog?: PostHogClient; }) { this.config = config; this.logger = logger; this.internalHooks = internalHooks; this.userRepository = repositories.User; this.settingsRepository = repositories.Settings; + this.postHog = postHog; } /** @@ -122,7 +129,7 @@ export class OwnerController { void this.internalHooks.onInstanceOwnerSetup({ user_id: userId }); - return sanitizeUser(owner); + return withFeatureFlags(this.postHog, sanitizeUser(owner)); } @Post('/dismiss-banner') diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index 1cf1ba0c39715..b3f8325fa94b3 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -83,6 +83,7 @@ declare global { people?: { set?(metadata: IDataObject): void; }; + debug?(): void; }; analytics?: { track(event: string, proeprties?: ITelemetryTrackProperties): void; diff --git a/packages/editor-ui/src/api/users.ts b/packages/editor-ui/src/api/users.ts index 74b717f280905..6f6d9bd86797d 100644 --- a/packages/editor-ui/src/api/users.ts +++ b/packages/editor-ui/src/api/users.ts @@ -28,7 +28,7 @@ export async function logout(context: IRestApiContext): Promise { export async function setupOwner( context: IRestApiContext, params: { firstName: string; lastName: string; email: string; password: string }, -): Promise { +): Promise { return makeRestApiRequest(context, 'POST', '/owner/setup', params as unknown as IDataObject); } diff --git a/packages/editor-ui/src/stores/users.store.ts b/packages/editor-ui/src/stores/users.store.ts index 74e3672969171..792c815a2c6cd 100644 --- a/packages/editor-ui/src/stores/users.store.ts +++ b/packages/editor-ui/src/stores/users.store.ts @@ -197,6 +197,7 @@ export const useUsersStore = defineStore(STORES.USERS, { this.addUsers([user]); this.currentUserId = user.id; settingsStore.stopShowingSetupPage(); + usePostHog().init(user.featureFlags); } }, async validateSignupToken(params: { @@ -218,9 +219,8 @@ export const useUsersStore = defineStore(STORES.USERS, { if (user) { this.addUsers([user]); this.currentUserId = user.id; + usePostHog().init(user.featureFlags); } - - usePostHog().init(user.featureFlags); }, async sendForgotPasswordEmail(params: { email: string }): Promise { const rootStore = useRootStore(); From 9706382840e3fceef0e0f3ebbe4615c87504f12b Mon Sep 17 00:00:00 2001 From: ricardo Date: Wed, 16 Aug 2023 19:22:47 -0400 Subject: [PATCH 9/9] send AI code generation finished event to PostHog --- packages/editor-ui/src/plugins/telemetry/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/src/plugins/telemetry/index.ts b/packages/editor-ui/src/plugins/telemetry/index.ts index 0cbe3b13011d1..bfcba55ed32b7 100644 --- a/packages/editor-ui/src/plugins/telemetry/index.ts +++ b/packages/editor-ui/src/plugins/telemetry/index.ts @@ -128,7 +128,7 @@ export class Telemetry { properties.session_id = useRootStore().sessionId; switch (event) { case 'askAi.generationFinished': - this.track('Ai code generation finished', properties); + this.track('Ai code generation finished', properties, { withPostHog: true }); case 'ask.generationClicked': this.track('User clicked on generate code button', properties); default: