add umami analytics loader

This commit is contained in:
Elijah Duffy
2025-12-16 17:21:40 -08:00
parent 086326326c
commit 1ead8431a7
3 changed files with 91 additions and 1 deletions

78
src/lib/Umami.svelte Normal file
View File

@@ -0,0 +1,78 @@
<script lang="ts">
import { dev } from '$app/environment';
import { onMount } from 'svelte';
import type { TrackingManager } from './tracking.svelte.ts';
interface Props {
/**
* The URL of the Umami instance. For example: https://umami.example.com.
* Do not include a trailing slash, the script path will be appended
* automatically (default: /script.js).
*/
umamiURL: string;
/** Website ID to associate tracking data as configured in Umami */
websiteID: string;
/**
* Tracking manager to handle user consent for tracking. If omitted,
* tracking will always be enabled.
*/
trackingManager?: TrackingManager;
}
let { umamiURL, websiteID, trackingManager }: Props = $props();
const consentGranted = $derived(trackingManager ? trackingManager.consent === true : true);
// Development overrides to prevent dirty analytics
const devConsoleTag = $derived(`[dev][consent: ${consentGranted ? 'granted' : 'revoked'}]`);
const devOverride = {
track: (...args: unknown[]): Promise<string> | undefined => {
console.log(`${devConsoleTag}: Track called with:`, ...args);
return undefined;
},
identify: (...args: unknown[]): Promise<void> => {
console.log(`${devConsoleTag}: Identify called with:`, ...args);
return Promise.resolve();
}
};
// No-consent quiet override
const noConsentOverride = {
track: (..._args: unknown[]): Promise<string> | undefined => {
return undefined;
},
identify: (..._args: unknown[]): Promise<void> => {
return Promise.resolve();
}
};
// If a tracking manager is provided, use it to manage consent state
$effect(() => {
if (trackingManager) {
trackingManager.createService({
onConsent: () => {
return true;
},
onRevoke: () => {
window.umami = noConsentOverride;
return true;
}
});
}
});
if (dev) console.log('[dev]: Umami tracking disabled');
onMount(() => {
if (dev) {
// In development mode, override the umami global object
window.umami = devOverride;
}
});
</script>
<svelte:head>
{#if !dev && consentGranted}
<script defer src="{umamiURL}/script.js" data-website-id={websiteID}></script>
{/if}
</svelte:head>