import type { AnalyticsProviderConfig, AnalyticsProvider } from '@nuxt/schema' type ScriptAttributes = { src?: string defer?: boolean async?: boolean id?: string innerHTML?: string [key: string]: string | boolean | number | undefined } // Keys read by the provider templates themselves. Anything else in a provider // config is forwarded to the tracker script as a `data-*` attribute. const CONSUMED_KEYS = ['provider', 'code', 'apiUrl', 'scriptUrl'] export const useAnalytics = () => { const config = useAppConfig() const providers = (config.analytics?.providers || []) as AnalyticsProviderConfig[] const getProviderScript = (provider: AnalyticsProviderConfig): ScriptAttributes[] => { const baseScripts: Record = { hakanai: [{ src: 'https://tracker.hakanai.io/hakanai.min.js', defer: true, 'data-site': provider.code, }], blogtally: [{ src: 'https://tracker.hakanai.io/hakanai.min.js', defer: true, 'data-site': provider.code, }], pirsch: [{ src: 'https://api.pirsch.io/pa.js', id: 'pianjs', defer: true, 'data-code': provider.code, }], plausible: [{ src: 'https://plausible.io/js/script.js', defer: true, 'data-domain': provider.code, }], umami: [{ src: 'https://cloud.umami.is/script.js', 'data-website-id': provider.code, defer: true, }], fathom: [{ src: 'https://cdn.usefathom.com/script.js', 'data-site': provider.code, defer: true, }], google: [ { src: `https://www.googletagmanager.com/gtag/js?id=${provider.code}`, async: true, defer: true, }, { innerHTML: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${provider.code}'); `, }, ], openpanel: [ { src: 'https://openpanel.dev/op1.js', defer: true, async: true, }, { innerHTML: ` window.op = window.op || function(...args){(window.op.q = window.op.q || []).push(args);}; window.op('init', { clientId: '${provider.code}',${provider.apiUrl ? `\n apiUrl: '${provider.apiUrl}',` : ''} trackScreenViews: true, trackOutgoingLinks: true, trackAttributes: true, }); `, }, ], } const scripts = baseScripts[provider.provider] || [] if (scripts.length > 0) { const extraParams = Object.entries(provider).reduce((acc, [key, value]) => { if (!CONSUMED_KEYS.includes(key)) { const attributeKey = key.startsWith('data-') ? key : `data-${key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`)}` acc[attributeKey] = value } return acc }, {} as Record) scripts[0] = { ...scripts[0], ...extraParams } // Self-hosted instances serve the tracker from their own domain. if (provider.scriptUrl) { scripts[0].src = provider.scriptUrl } } return scripts } providers.forEach(provider => { const scripts = getProviderScript(provider) if (scripts.length > 0) { useHead({ script: scripts, }) } }) }