import { useEffect } from 'react'; import { getAppConfig } from '@/lib/config'; const SCRIPT_ELEMENT_ID = 'umami-analytics-script'; /** * Injects the self-hosted Umami tracking script when both the script URL and the website ID are * configured at build time. Renders nothing. * * A component rather than a tag in index.html, because the website ID is a build-time variable * and index.html cannot read import.meta.env. It also makes the "never in development" and "once * only" rules testable. * * `Do Not Track` is deliberately not consulted: Umami sets no cookies and collects no personal * data, and this SPA's audience is a known set of operators, so honouring DNT would reduce data * without protecting anyone. A conscious choice rather than an omission. */ export function UmamiAnalytics() { useEffect(() => { const { umamiScriptUrl, umamiWebsiteId } = getAppConfig(); // Never in local development, regardless of configuration, so local testing does not // pollute the real visitor analytics. if (import.meta.env.DEV || !umamiScriptUrl || !umamiWebsiteId) { return; } if (document.getElementById(SCRIPT_ELEMENT_ID) !== null) { return; } const script = document.createElement('script'); script.id = SCRIPT_ELEMENT_ID; script.src = umamiScriptUrl; script.defer = true; script.setAttribute('data-website-id', umamiWebsiteId); document.head.appendChild(script); // Deliberately no cleanup removing the script. Under StrictMode the double-invocation // would become inject -> remove -> inject, and removing the element does not unregister // the listeners Umami already installed — so the first page view can be counted twice. // This component lives for the application's lifetime and has nothing to clean up; the // duplicate guard above handles re-invocation on its own. }, []); return null; }