UNPKG

nuxt-utm

Version:

A Nuxt 3/4 module for tracking UTM parameters.

118 lines (117 loc) 3.85 kB
import { ref, readonly } from "vue"; import { readLocalData, getSessionID, getUtmParams, getAdditionalInfo, isRepeatedEntry, urlHasGCLID, getGCLID } from "./utm.js"; import { defineNuxtPlugin, useRuntimeConfig } from "#app"; const LOCAL_STORAGE_KEY = "nuxt-utm-data"; const SESSION_ID_KEY = "nuxt-utm-session-id"; const TRACKING_ENABLED_KEY = "nuxt-utm-tracking-enabled"; export default defineNuxtPlugin((nuxtApp) => { const config = useRuntimeConfig(); const data = ref([]); const logHookError = (hookName, error) => { console.error(`[nuxt-utm] Hook "${hookName}" failed`, error); return false; }; const runBeforeTrackHook = async (context) => { try { await nuxtApp.callHook("utm:before-track", context); return true; } catch (error) { return logHookError("utm:before-track", error); } }; const runBeforePersistHook = async (dataObject) => { try { await nuxtApp.callHook("utm:before-persist", dataObject); return true; } catch (error) { return logHookError("utm:before-persist", error); } }; const runTrackedHook = async (dataObject) => { try { await nuxtApp.callHook("utm:tracked", dataObject); return true; } catch (error) { return logHookError("utm:tracked", error); } }; const getInitialTrackingState = () => { if (typeof window === "undefined") return config.public.utm?.trackingEnabled ?? true; const storedState = localStorage.getItem(TRACKING_ENABLED_KEY); if (storedState !== null) { return storedState === "true"; } return config.public.utm?.trackingEnabled ?? true; }; const trackingEnabled = ref(getInitialTrackingState()); const processUtmData = async () => { if (typeof window === "undefined") return; if (!trackingEnabled.value) return; data.value = readLocalData(LOCAL_STORAGE_KEY); const query = nuxtApp._route.query; const route = nuxtApp._route; const beforeTrackContext = { route, query, skip: false }; const beforeTrackSucceeded = await runBeforeTrackHook(beforeTrackContext); if (!beforeTrackSucceeded || beforeTrackContext.skip) return; const sessionId = getSessionID(SESSION_ID_KEY); const utmParams = getUtmParams(query); const additionalInfo = getAdditionalInfo(); const timestamp = (/* @__PURE__ */ new Date()).toISOString(); const dataObject = { timestamp, utmParams, additionalInfo, sessionId }; if (urlHasGCLID(query)) { dataObject.gclidParams = getGCLID(query); } const beforePersistSucceeded = await runBeforePersistHook(dataObject); if (!beforePersistSucceeded) return; if (isRepeatedEntry(data, dataObject)) return; data.value.unshift(dataObject); localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(data.value)); await runTrackedHook(dataObject); }; const enableTracking = () => { trackingEnabled.value = true; if (typeof window !== "undefined") { localStorage.setItem(TRACKING_ENABLED_KEY, "true"); processUtmData(); } }; const disableTracking = () => { trackingEnabled.value = false; if (typeof window !== "undefined") { localStorage.setItem(TRACKING_ENABLED_KEY, "false"); } }; const clearTrackingData = () => { data.value = []; if (typeof window !== "undefined") { localStorage.removeItem(LOCAL_STORAGE_KEY); sessionStorage.removeItem(SESSION_ID_KEY); } }; if (typeof window !== "undefined") { data.value = readLocalData(LOCAL_STORAGE_KEY); } nuxtApp.hook("app:mounted", processUtmData); return { provide: { utm: readonly(data), utmTrackingEnabled: readonly(trackingEnabled), utmEnableTracking: enableTracking, utmDisableTracking: disableTracking, utmClearData: clearTrackingData } }; });