import { useEffect, useRef } from 'react'; import { apiUrl } from '../lib/api'; /** * Sends a telemetry beacon every 30 seconds with session duration * and the number of active filters (parsed from the URL `f` param). * On the first beacon, also sends the entry path and referrer domain. */ export function useTelemetry() { const startTime = useRef(Date.now()); const entryPath = useRef(window.location.pathname); const referrer = useRef(extractReferrerDomain()); const sentEntry = useRef(false); useEffect(() => { const send = () => { const sessionSeconds = Math.round((Date.now() - startTime.current) / 1000); // Count active filters from URL (filters are encoded as `f=name:min:max;;name:val`) const params = new URLSearchParams(window.location.search); const filterStr = params.get('f') || ''; const filterCount = filterStr ? filterStr.split(';;').length : 0; const payload: Record = { session_seconds: sessionSeconds, filter_count: filterCount, }; // Include entrypoint info on first beacon only if (!sentEntry.current) { payload.entry_path = entryPath.current; payload.referrer = referrer.current; sentEntry.current = true; } navigator.sendBeacon( apiUrl('telemetry'), new Blob([JSON.stringify(payload)], { type: 'application/json' }) ); }; const interval = setInterval(send, 30_000); return () => clearInterval(interval); }, []); } /** Extract the referrer domain, or "direct" if none / same-origin. */ function extractReferrerDomain(): string { if (!document.referrer) return 'direct'; try { const url = new URL(document.referrer); // Same-origin navigation isn't a real external referrer if (url.origin === window.location.origin) return 'direct'; return url.hostname; } catch { return 'direct'; } }