wip try to encapsulate captureEvent calls in telemetry

This commit is contained in:
lebaudantoine
2026-08-07 16:10:05 +02:00
parent 993efec027
commit 7514bff7c1
9 changed files with 44 additions and 127 deletions
@@ -1,5 +1,21 @@
import { getPosthog } from './utils'
export const captureEvent = (
event: string,
props?: Record<string, unknown>
) => {
void getPosthog()
.then((ph) => {
ph.capture(event, props)
})
.catch(() => {
/* telemetry must never break the app */
})
if (import.meta.env.DEV) {
console.warn(`[telemetry] ${event}`, props)
}
}
export type LogCode =
// media
| 'join_preview_failure'
@@ -16,7 +16,6 @@ import {
notifyRecordingSaveInProgress,
useNotifyParticipants,
} from '@/features/notifications'
import posthog from 'posthog-js'
import { useConfig } from '@/api/useConfig'
import { NoAccessView } from './NoAccessView'
import { ControlsButton } from './ControlsButton'
@@ -29,7 +28,7 @@ import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
import { FeatureFlags } from '@/features/analytics/enums'
import { LimitDescription } from './LimitDescription'
import { reportError } from '@/features/analytics/telemetry'
import { captureEvent, reportError } from '@/features/analytics/telemetry'
export const ScreenRecordingSidePanel = () => {
const { data } = useConfig()
@@ -64,7 +63,7 @@ export const ScreenRecordingSidePanel = () => {
await notifyParticipants({
type: NotificationType.ScreenRecordingRequested,
})
posthog.capture('screen-recording-requested', {})
captureEvent('screen-recording-requested', {})
}
const handleScreenRecording = async () => {
@@ -101,7 +100,7 @@ export const ScreenRecordingSidePanel = () => {
await notifyParticipants({
type: NotificationType.ScreenRecordingStarted,
})
posthog.capture('screen-recording-started', {
captureEvent('screen-recording-started', {
includeTranscript: includeTranscript,
language: selectedLanguageKey,
})
@@ -17,7 +17,6 @@ import {
useNotifyParticipants,
notifyRecordingSaveInProgress,
} from '@/features/notifications'
import posthog from 'posthog-js'
import { useConfig } from '@/api/useConfig'
import { VStack } from '@/styled-system/jsx'
import { Checkbox } from '@/primitives/Checkbox.tsx'
@@ -35,7 +34,7 @@ import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
import { LimitDescription } from './LimitDescription'
import { openSettingsDialog } from '@/stores/settings'
import { reportError } from '@/features/analytics/telemetry'
import { captureEvent, reportError } from '@/features/analytics/telemetry'
export const TranscriptSidePanel = () => {
const { data } = useConfig()
@@ -77,7 +76,7 @@ export const TranscriptSidePanel = () => {
await notifyParticipants({
type: NotificationType.TranscriptionRequested,
})
posthog.capture('transcript-requested', {})
captureEvent('transcript-requested', {})
}
const handleTranscript = async () => {
@@ -122,7 +121,7 @@ export const TranscriptSidePanel = () => {
await notifyParticipants({
type: NotificationType.TranscriptionStarted,
})
posthog.capture('transcript-started', {
captureEvent('transcript-started', {
includeScreenRecording: includeScreenRecording,
language: selectedLanguageKey,
})
@@ -26,8 +26,7 @@ import { css } from '@/styled-system/css'
import { BackgroundProcessorFactory } from '../livekit/components/blur'
import { LocalUserChoices } from '@/stores/userChoices'
import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert'
import { reportError } from '@/features/analytics/telemetry'
import { usePostHog } from 'posthog-js/react'
import { captureEvent, reportError } from '@/features/analytics/telemetry'
import { useConfig } from '@/api/useConfig'
import { isFireFox } from '@/utils/livekit'
import { useIsMobile } from '@/utils/useIsMobile'
@@ -48,7 +47,6 @@ export const Conference = ({
mode?: 'join' | 'create'
initialRoomData?: ApiRoom
}) => {
const posthog = usePostHog()
const { data: apiConfig } = useConfig()
const { userChoices: userConfig } = usePersistentUserChoices() as {
@@ -58,8 +56,8 @@ export const Conference = ({
const { username } = useSnapshot(userStore)
useEffect(() => {
posthog.capture('visit-room', { slug: roomId })
}, [roomId, posthog])
captureEvent('visit-room', { slug: roomId })
}, [roomId])
const fetchKey = [keys.room, roomId]
const [isConnectionWarmedUp, setIsConnectionWarmedUp] = useState(false)
@@ -1,13 +1,12 @@
import { Button, H, Input, Text, TextArea } from '@/primitives'
import { Button, H, Text, TextArea } from '@/primitives'
import { useEffect, useMemo, useState } from 'react'
import { cva } from '@/styled-system/css'
import { useTranslation } from 'react-i18next'
import { styled, VStack } from '@/styled-system/jsx'
import { usePostHog } from 'posthog-js/react'
import type { PostHog } from 'posthog-js'
import { Button as RACButton } from 'react-aria-components'
import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalyticsEnabled'
import type { CandidateInfo } from '@/stores/connectionObserver'
import { captureEvent } from '@/features/analytics/telemetry'
const Card = styled('div', {
base: {
@@ -72,11 +71,9 @@ const labelRecipe = cva({
})
const OpenFeedback = ({
posthog,
onNext,
metadata,
}: {
posthog: PostHog
onNext: () => void
metadata?: Record<string, unknown>
}) => {
@@ -90,7 +87,7 @@ const OpenFeedback = ({
const onSubmit = () => {
try {
posthog.capture('open-feedback', {
captureEvent('open-feedback', {
feedback,
...metadata,
})
@@ -141,12 +138,10 @@ const OpenFeedback = ({
}
const RateQuality = ({
posthog,
onNext,
metadata,
maxRating = 5,
}: {
posthog: PostHog
onNext: () => void
metadata?: Record<string, unknown>
maxRating?: number
@@ -160,7 +155,7 @@ const RateQuality = ({
const onSubmit = () => {
try {
posthog.capture('quality-rating', {
captureEvent('quality-rating', {
rating: selectedRating,
...metadata,
})
@@ -243,67 +238,6 @@ const ConfirmationMessage = ({ onNext }: { onNext: () => void }) => {
)
}
const AuthenticationMessage = ({
onNext,
posthog,
}: {
onNext: () => void
posthog: PostHog
}) => {
const { t } = useTranslation('rooms', { keyPrefix: 'authenticationMessage' })
const [email, setEmail] = useState('')
const onSubmit = () => {
posthog.people.set({ unsafe_email: email })
onNext()
}
return (
<Card
style={{
maxWidth: '380px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
}}
>
<H lvl={3}>{t('heading')}</H>
<Input
id="emailInput"
name="email"
placeholder={t('placeholder')}
required
value={email}
onChange={(e) => setEmail(e.target.value)}
style={{
marginBottom: '1rem',
}}
/>
<VStack gap="0.5">
<Button
variant="primary"
size="sm"
fullWidth
isDisabled={!email}
onPress={onSubmit}
>
{t('submit')}
</Button>
<Button
invisible
variant="secondary"
size="sm"
fullWidth
onPress={onNext}
>
{t('ignore')}
</Button>
</VStack>
</Card>
)
}
type RatingMetadata = {
room_id?: string
pc_publisher?: CandidateInfo
@@ -318,12 +252,6 @@ export const Rating = ({
metadata: RatingMetadata
}) => {
const isAnalyticsEnabled = useIsAnalyticsEnabled()
const posthog = usePostHog()
const isUserAnonymous = useMemo(() => {
return posthog.get_property('$user_state') == 'anonymous'
}, [posthog])
const [step, setStep] = useState(0)
const sessionId = useMemo(() => crypto.randomUUID(), [])
@@ -339,37 +267,14 @@ export const Rating = ({
if (!isAnalyticsEnabled) return
if (step == 0) {
return (
<RateQuality
posthog={posthog}
onNext={() => setStep(step + 1)}
metadata={metadata}
/>
)
return <RateQuality onNext={() => setStep(step + 1)} metadata={metadata} />
}
if (step == 1) {
return (
<OpenFeedback
posthog={posthog}
onNext={() => setStep(step + 1)}
metadata={metadata}
/>
)
return <OpenFeedback onNext={() => setStep(step + 1)} metadata={metadata} />
}
if (step == 2) {
return isUserAnonymous ? (
<AuthenticationMessage
posthog={posthog}
onNext={() => setStep(step + 1)}
/>
) : (
<ConfirmationMessage onNext={() => setStep(0)} />
)
}
if (step == 3) {
return <ConfirmationMessage onNext={() => setStep(0)} />
}
}
@@ -11,10 +11,10 @@ import { DisconnectReason, RoomEvent } from 'livekit-client'
import { userPreferencesStore } from '@/stores/userPreferences'
import { connectionObserverStore } from '@/stores/connectionObserver'
import posthog from 'posthog-js'
import { useFeatureFlagEnabled } from 'posthog-js/react'
import { isMobileBrowser } from '@livekit/components-core'
import { FeatureFlags } from '@/features/analytics/enums'
import { captureEvent } from '@/features/analytics/telemetry'
const CANDIDATE_POLL_INTERVAL_MS = 5000
@@ -182,23 +182,23 @@ export const ConnectionObserver = () => {
// total session duration from first connect to final disconnect.
if (connectionStartTimeRef.current != null) return
connectionStartTimeRef.current = Date.now()
posthog.capture('connection-event')
captureEvent('connection-event')
}
const handleReconnect = () => {
posthog.capture('reconnect-event')
captureEvent('reconnect-event')
}
const handleReconnected = () => {
posthog.capture('reconnected-event')
captureEvent('reconnected-event')
}
const handleSignalingConnect = () => {
posthog.capture('signaling-connect-event')
captureEvent('signaling-connect-event')
}
const handleSignalingReconnect = () => {
posthog.capture('signaling-reconnect-event')
captureEvent('signaling-reconnect-event')
}
const handleDisconnect = (
@@ -206,7 +206,7 @@ export const ConnectionObserver = () => {
) => {
const connectionEndTime = Date.now()
posthog.capture('disconnect-event', {
captureEvent('disconnect-event', {
// Calculate total session duration from first connection to final disconnect
// This duration is sensitive to refreshing the page.
sessionDuration: connectionStartTimeRef.current
@@ -1,5 +1,4 @@
import type { ProcessorOptions, Track } from 'livekit-client'
import posthog from 'posthog-js'
import {
FilesetResolver,
ImageSegmenter,
@@ -18,6 +17,7 @@ import {
type ProcessorType,
MEDIAPIPE_PATH_WASM,
} from '.'
import { captureEvent } from '@/features/analytics/telemetry.ts'
const PROCESSING_WIDTH = 256
const PROCESSING_HEIGHT = 144
@@ -100,7 +100,7 @@ export class BackgroundCustomProcessor implements BackgroundProcessorInterface {
await this.initSegmenter()
this._initWorker()
posthog.capture('firefox-blurring-init')
captureEvent('firefox-blurring-init', {})
}
_initVirtualBackgroundImage() {
@@ -1,5 +1,4 @@
import type { ProcessorOptions, Track, TrackProcessor } from 'livekit-client'
import posthog from 'posthog-js'
import {
FilesetResolver,
FaceLandmarker,
@@ -16,6 +15,7 @@ import {
ProcessorType,
MEDIAPIPE_PATH_WASM,
} from '.'
import { captureEvent } from '@/features/analytics/telemetry'
const PROCESSING_WIDTH = 256 * 3
const PROCESSING_HEIGHT = 144 * 3
@@ -101,7 +101,7 @@ export class FaceLandmarksProcessor implements TrackProcessor<Track.Kind> {
await this.initFaceLandmarker()
this._initWorker()
posthog.capture('face-landmarks-init')
captureEvent('face-landmarks-init', {})
}
_initWorker() {
@@ -11,7 +11,6 @@ import { useTranslation } from 'react-i18next'
import { SoundTester } from '@/components/SoundTester'
import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker'
import { useNoiseReductionAvailable } from '@/features/rooms/livekit/hooks/useNoiseReductionAvailable'
import posthog from 'posthog-js'
import { RowWrapper } from './layout/RowWrapper'
import { useSnapshot } from 'valtio'
import {
@@ -20,6 +19,7 @@ import {
saveNoiseReductionEnabled,
userChoicesStore,
} from '@/stores/userChoices'
import { captureEvent } from '@/features/analytics/telemetry'
export type AudioTabProps = Pick<DialogProps, 'onOpenChange'> &
Pick<TabPanelProps, 'id'>
@@ -128,7 +128,7 @@ export const AudioTab = ({ id }: AudioTabProps) => {
isSelected={noiseReductionEnabled}
onChange={(v) => {
saveNoiseReductionEnabled(v)
if (v) posthog.capture('noise-reduction-init')
if (v) captureEvent('noise-reduction-init')
}}
>
{t('audio.noiseReduction.label')}