UNPKG

@lukulent/svelte-umami

Version:

[![MadeWithSvelte.com shield](https://madewithsvelte.com/storage/repo-shields/5086-shield.svg)](https://madewithsvelte.com/p/svelte-umami/shield-link)

169 lines (168 loc) 6.74 kB
import { status } from './stores/umami'; import { get } from 'svelte/store'; // https://github.com/flexdinesh/browser-or-node const browser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; /** * Track a page view with and without custom properties * @param properties * @returns */ export function trackPageView(properties) { if (!browser) return Promise.resolve(''); if ([undefined, 'error', 'removed'].includes(get(status))) return Promise.resolve('Umami not found.'); return waitForUmami().then((umami) => { if (properties) { return umami.track((props) => ({ ...props, ...properties })); } else { return umami.track(); } }); } async function waitForUmami() { let count = 50; // try max 5 seconds while (!window.umami) { if ([undefined, 'error', 'removed'].includes(get(status)) || count > 0) { return { track: () => Promise.resolve('Umami not found.') }; } await new Promise((resolve) => setTimeout(resolve, 100)); count--; } return window.umami; } /** * Track an event with a given name * @param eventName Note: event names will be truncated past 50 characters * @param eventData Note: Event Data Limits Event Data can work with any JSON data. There are a few rules in place to maintain performance. - Numbers have a max precision of 4. - Strings have a max length of 500. - Arrays are converted to a String, with the same max length of 500. - Objects have a max of 50 properties. Arrays are considered 1 property. - When tracking events, the default properties are included in the payload. * @returns */ export function trackEvent(eventName, eventData) { if (!browser) return Promise.resolve(''); if ([undefined, 'error', 'removed'].includes(get(status))) return Promise.resolve('Umami not found.'); return waitForUmami().then((umami) => { if (eventData) { return umami.track(eventName, eventData); } else { return umami.track(eventName); } }); } /** * Track an event with a given name and custom properties * @param eventName Note: event names will be truncated past 50 characters * @param properties the default properties you want to overwrite * @param eventData Note: Event Data Limits Event Data can work with any JSON data. There are a few rules in place to maintain performance. - Numbers have a max precision of 4. - Strings have a max length of 500. - Arrays are converted to a String, with the same max length of 500. - Objects have a max of 50 properties. Arrays are considered 1 property. - When tracking events, the default properties are included in the payload. * @returns */ export function trackEventWithProperties(eventName, properties, eventData) { if (!browser) return Promise.resolve(''); if ([undefined, 'error', 'removed'].includes(get(status))) return Promise.resolve('Umami not found.'); return waitForUmami().then((umami) => { if (eventData) { return umami.track((props) => ({ ...props, ...properties, name: eventName, data: eventData })); } else { return umami.track((props) => ({ ...props, ...properties, name: eventName })); } }); } const SCRIPT_ID = 'umami_analytics_script'; /** * Adding the script would fail for example if the user is running * an ad blocker. This Promise can handle that case. */ async function registerUmamiScript(websiteID, srcURL = 'https://eu.umami.is/script.js') { return new Promise((resolve, reject) => { const head = document.head || document.getElementsByTagName('head')[0]; const script = document.createElement('script'); script.id = SCRIPT_ID; script.async = true; script.defer = true; script.setAttribute('data-website-id', websiteID); script.setAttribute('data-testid', SCRIPT_ID); script.src = srcURL; const element = head.appendChild(script); script.onload = resolve; script.onerror = reject; return element; }); } export async function registerUmami(websiteID, srcURL, configuration) { // We add the script only once even when the component rendered twice and don't run while SSR. if (!browser || window.document.getElementById(SCRIPT_ID)) return; try { registerUmamiScript(websiteID, srcURL); const umamiScript = document.getElementById(SCRIPT_ID); if (umamiScript) { setScriptSettingsProps(umamiScript, configuration); } else { console.error('umami script not found'); } } catch { console.error('umami failure'); const s = window.document.getElementById(SCRIPT_ID); if (s) { s.remove(); } } } function setScriptSettingsProps(scriptElem, config) { if (config['data-host-url']) scriptElem.setAttribute('data-host-url', config['data-host-url']); if (config['data-auto-track'] !== undefined && !config['data-auto-track']) scriptElem.setAttribute('data-auto-track', 'false'); if (config['data-cache']) scriptElem.setAttribute('data-cache', 'true'); if (config['data-domains']) scriptElem.setAttribute('data-domains', config['data-domains']); if (config['data-exclude-search']) scriptElem.setAttribute('data-exclude-search', 'true'); if (config['data-tag']) scriptElem.setAttribute('data-tag', config['data-tag']); } /** * Svelte Event Handler, which tracks the event within UmamiAnalytics * @param e: Event */ export function handleEvent(e) { // The target property returns the element on which the event occurred, opposed to the currentTarget property, which returns the element whose event listener triggered the event. const targetUmamiId = e.target?.getAttribute('data-umami-event'); const currentTargetUmamiId = e.currentTarget?.getAttribute('data-umami-event'); const targetId = e.target?.getAttribute('id'); const currentTargetId = e.currentTarget?.getAttribute('id'); trackEvent(`${targetUmamiId ?? currentTargetUmamiId ?? targetId ?? currentTargetId} ${e.type}`, e); }