mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
feat: send missing node data to ClickHouse (#10132)
## Summary - When users open/import a workflow with missing nodes, we already track this via Mixpanel - This adds a parallel fire-and-forget POST to `/api/internal/cloud_analytics` so the data also lands in **ClickHouse** as `frontend:missing_nodes_detected` events - Payload includes `missing_class_types[]`, `missing_count`, and `source` (file_button/file_drop/template/unknown) ## Motivation The frontend is where the **high-value** missing node signal lives — most users see "missing nodes" and never submit. The backend only catches the rare case where someone submits anyway. This change captures both sides. Companion cloud PR: https://github.com/Comfy-Org/cloud/pull/2886 ## Changes - `MixpanelTelemetryProvider.ts`: Added `reportMissingNodesToClickHouse()` private method, called from `trackWorkflowImported()` and `trackWorkflowOpened()` - Only fires when `missing_node_count > 0` - Fire-and-forget (`.catch(() => {})`) — no impact on user experience - Uses existing `api.fetchApi()` which handles auth automatically ## Test plan - [ ] Open a workflow with missing nodes → verify `frontend:missing_nodes_detected` event appears in ClickHouse - [ ] Open a workflow with no missing nodes → verify no event is sent (check network tab) - [ ] Verify Mixpanel tracking still works as before 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10132-feat-send-missing-node-data-to-ClickHouse-3266d73d365081559db5ed3efde33e95) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -25,13 +25,15 @@ export async function initTelemetry(): Promise<void> {
|
||||
{ MixpanelTelemetryProvider },
|
||||
{ GtmTelemetryProvider },
|
||||
{ ImpactTelemetryProvider },
|
||||
{ PostHogTelemetryProvider }
|
||||
{ PostHogTelemetryProvider },
|
||||
{ ClickHouseTelemetryProvider }
|
||||
] = await Promise.all([
|
||||
import('./TelemetryRegistry'),
|
||||
import('./providers/cloud/MixpanelTelemetryProvider'),
|
||||
import('./providers/cloud/GtmTelemetryProvider'),
|
||||
import('./providers/cloud/ImpactTelemetryProvider'),
|
||||
import('./providers/cloud/PostHogTelemetryProvider')
|
||||
import('./providers/cloud/PostHogTelemetryProvider'),
|
||||
import('./providers/cloud/ClickHouseTelemetryProvider')
|
||||
])
|
||||
|
||||
const registry = new TelemetryRegistry()
|
||||
@@ -39,6 +41,7 @@ export async function initTelemetry(): Promise<void> {
|
||||
registry.registerProvider(new GtmTelemetryProvider())
|
||||
registry.registerProvider(new ImpactTelemetryProvider())
|
||||
registry.registerProvider(new PostHogTelemetryProvider())
|
||||
registry.registerProvider(new ClickHouseTelemetryProvider())
|
||||
|
||||
setTelemetryRegistry(registry)
|
||||
})()
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { api } from '@/scripts/api'
|
||||
|
||||
import type { TelemetryProvider, WorkflowImportMetadata } from '../../types'
|
||||
|
||||
/**
|
||||
* ClickHouse Telemetry Provider - Cloud Build Implementation
|
||||
*
|
||||
* Sends observability events to the cloud backend's ClickHouse pipeline
|
||||
* via POST /api/internal/cloud_analytics. Currently tracks missing node
|
||||
* data when users open/import workflows with unsupported nodes.
|
||||
*
|
||||
* This provider is separate from Mixpanel because ClickHouse is the
|
||||
* canonical store for post-hoc analytics (per observability philosophy).
|
||||
*
|
||||
* CRITICAL: OSS Build Safety
|
||||
* This file is tree-shaken away in OSS builds (DISTRIBUTION unset).
|
||||
*/
|
||||
export class ClickHouseTelemetryProvider implements TelemetryProvider {
|
||||
trackWorkflowImported(metadata: WorkflowImportMetadata): void {
|
||||
this.reportMissingNodes(metadata)
|
||||
}
|
||||
|
||||
trackWorkflowOpened(metadata: WorkflowImportMetadata): void {
|
||||
this.reportMissingNodes(metadata)
|
||||
}
|
||||
|
||||
private reportMissingNodes(metadata: WorkflowImportMetadata): void {
|
||||
if (metadata.missing_node_count <= 0) return
|
||||
|
||||
api
|
||||
.fetchApi('/internal/cloud_analytics', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
event_name: 'node_missing',
|
||||
event_data: {
|
||||
missing_class_types: metadata.missing_node_types,
|
||||
missing_count: metadata.missing_node_count,
|
||||
source: metadata.open_source ?? 'unknown'
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user