From e6caa0a2fd6c09cc4c86e1a98e15a0834fd0b1c8 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Wed, 11 Jun 2025 17:55:10 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=88(frontend)=20add=20analytics=20for?= =?UTF-8?q?=20disconnect/reconnect=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track connection issues to identify user problems. Skip client-initiated disconnects (normal flow). Disconnect events provide richer data than reconnect events which lack reason details. Next: Add error screen for JOIN_FAILURE disconnects to trigger support workflow for users experiencing connection problems. --- .../livekit/hooks/useConnectionObserver.ts | 34 +++++++++++++++++++ .../rooms/livekit/prefabs/VideoConference.tsx | 3 ++ 2 files changed, 37 insertions(+) create mode 100644 src/frontend/src/features/rooms/livekit/hooks/useConnectionObserver.ts diff --git a/src/frontend/src/features/rooms/livekit/hooks/useConnectionObserver.ts b/src/frontend/src/features/rooms/livekit/hooks/useConnectionObserver.ts new file mode 100644 index 00000000..d01ed6bb --- /dev/null +++ b/src/frontend/src/features/rooms/livekit/hooks/useConnectionObserver.ts @@ -0,0 +1,34 @@ +import { useRoomContext } from '@livekit/components-react' +import { useEffect } from 'react' +import { DisconnectReason, RoomEvent } from 'livekit-client' +import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalyticsEnabled' +import posthog from 'posthog-js' + +export const useConnectionObserver = () => { + const room = useRoomContext() + + const isAnalyticsEnabled = useIsAnalyticsEnabled() + + useEffect(() => { + if (!isAnalyticsEnabled) return + + const handleReconnect = () => { + posthog.capture('reconnect-event') + } + + const handleDisconnect = ( + disconnectReason: DisconnectReason | undefined + ) => { + if (disconnectReason == DisconnectReason.CLIENT_INITIATED) return + posthog.capture('disconnect-event', { + reason: disconnectReason && DisconnectReason[disconnectReason], + }) + } + room.on(RoomEvent.Disconnected, handleDisconnect) + room.on(RoomEvent.Reconnecting, handleReconnect) + return () => { + room.off(RoomEvent.Disconnected, handleDisconnect) + room.off(RoomEvent.Reconnecting, handleReconnect) + } + }, [room, isAnalyticsEnabled]) +} diff --git a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx index 37cf2af8..4944ac7f 100644 --- a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx +++ b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx @@ -30,6 +30,7 @@ import { SidePanel } from '../components/SidePanel' import { useSidePanel } from '../hooks/useSidePanel' import { RecordingStateToast } from '@/features/recording' import { ScreenShareErrorModal } from '../components/ScreenShareErrorModal' +import { useConnectionObserver } from '../hooks/useConnectionObserver' const LayoutWrapper = styled( 'div', @@ -74,6 +75,8 @@ export function VideoConference({ ...props }: VideoConferenceProps) { const lastAutoFocusedScreenShareTrack = React.useRef(null) + useConnectionObserver() + const tracks = useTracks( [ { source: Track.Source.Camera, withPlaceholder: true },