diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index 0ebd0f491f3c7..280def7505c8e 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -380,6 +380,7 @@ export interface IInternalHooksClass { onServerStarted( diagnosticInfo: IDiagnosticInfo, firstWorkflowCreatedAt?: Date, + userId?: string, ): Promise; onPersonalizationSurveySubmitted(userId: string, answers: Record): Promise; onWorkflowCreated(userId: string, workflow: IWorkflowBase, publicApi: boolean): Promise; diff --git a/packages/cli/src/InternalHooks.ts b/packages/cli/src/InternalHooks.ts index 4221b2ac8c7e4..9a2503360065e 100644 --- a/packages/cli/src/InternalHooks.ts +++ b/packages/cli/src/InternalHooks.ts @@ -32,6 +32,7 @@ export class InternalHooksClass implements IInternalHooksClass { async onServerStarted( diagnosticInfo: IDiagnosticInfo, earliestWorkflowCreatedAt?: Date, + userId?: string, ): Promise { const info = { version_cli: diagnosticInfo.versionCli, @@ -45,9 +46,11 @@ export class InternalHooksClass implements IInternalHooksClass { n8n_binary_data_mode: diagnosticInfo.binaryDataMode, n8n_multi_user_allowed: diagnosticInfo.n8n_multi_user_allowed, smtp_set_up: diagnosticInfo.smtp_set_up, + user_id: userId, }; return Promise.all([ + this.telemetry.identify(info), this.telemetry.track('Instance started', { ...info, earliest_workflow_created: earliestWorkflowCreatedAt, diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 2a90700b73c60..ebabf5899fc17 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -1986,14 +1986,21 @@ export async function start(): Promise { smtp_set_up: config.getEnv('userManagement.emails.mode') === 'smtp', }; - void Db.collections - .Workflow!.findOne({ - select: ['createdAt'], - order: { createdAt: 'ASC' }, - }) - .then(async (workflow) => - InternalHooksManager.getInstance().onServerStarted(diagnosticInfo, workflow?.createdAt), - ); + const earliestWorkflow = await Db.collections.Workflow.findOne({ + select: ['createdAt', 'id'], + order: { createdAt: 'ASC' }, + }); + + const sharing = await Db.collections.SharedWorkflow.findOne({ + where: { workflow: { id: earliestWorkflow?.id } }, + relations: ['workflow'], + }); + + void InternalHooksManager.getInstance().onServerStarted( + diagnosticInfo, + earliestWorkflow?.createdAt, + sharing?.userId, + ); }); server.on('error', (error: Error & { code: string }) => { diff --git a/packages/cli/src/telemetry/index.ts b/packages/cli/src/telemetry/index.ts index 43824ff7e8a1a..ae8a263bab6ae 100644 --- a/packages/cli/src/telemetry/index.ts +++ b/packages/cli/src/telemetry/index.ts @@ -138,6 +138,38 @@ export class Telemetry { }); } + async identify(traits?: { + [key: string]: string | number | boolean | object | undefined | null; + }): Promise { + return new Promise((resolve) => { + if (this.postHog && traits?.user_id) { + this.postHog.identify({ + distinctId: [this.instanceId, traits.user_id].join('#'), + properties: { + ...traits, + instanceId: this.instanceId, + }, + }); + } + + if (this.rudderStack) { + this.rudderStack.identify( + { + userId: this.instanceId, + anonymousId: '000000000000', + traits: { + ...traits, + instanceId: this.instanceId, + }, + }, + resolve, + ); + } else { + resolve(); + } + }); + } + async track( eventName: string, properties: ITelemetryTrackProperties = {},