From a20760dfe27ff813b367e2e27804ff12ac652fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Gaudencio=20do=20R=C3=AAgo?= Date: Fri, 14 Feb 2025 18:09:02 -0300 Subject: [PATCH] Avoid multiple plausibles --- analytics/components/DecoAnalytics.tsx | 111 ++++++++++++++----------- 1 file changed, 61 insertions(+), 50 deletions(-) diff --git a/analytics/components/DecoAnalytics.tsx b/analytics/components/DecoAnalytics.tsx index c9c2fde9b..fdbf93a44 100644 --- a/analytics/components/DecoAnalytics.tsx +++ b/analytics/components/DecoAnalytics.tsx @@ -9,66 +9,77 @@ export interface Props { } declare global { interface Window { + plausibleInitialized: boolean; plausible: (name: string, params: { props: Record; }) => void; } } // This function should be self contained, because it is stringified! -const snippet = () => { - // Flags and additional dimentions - const props: Record = {}; - const trackPageview = () => - globalThis.window.plausible?.("pageview", { props }); - // Attach pushState and popState listeners - const originalPushState = history.pushState; - if (originalPushState) { - history.pushState = function () { - // @ts-ignore monkey patch - originalPushState.apply(this, arguments); - trackPageview(); - }; - addEventListener("popstate", trackPageview); - } - // 2000 bytes limit - const truncate = (str: string) => `${str}`.slice(0, 990); - // setup plausible script and unsubscribe - globalThis.window.DECO.events.subscribe((event) => { - if (!event || event.name !== "deco") { - return; +const snippet = (() => { + globalThis.window.plausibleInitialized = false; + return () => { + if (globalThis.window.plausibleInitialized) return; + globalThis.window.plausibleInitialized = true; + + // Flags and additional dimensions + const props: Record = {}; + const trackPageview = () => + globalThis.window.plausible?.("pageview", { props }); + + // Attach pushState and popState listeners + const originalPushState = history.pushState; + if (originalPushState) { + history.pushState = function () { + // @ts-ignore monkey patch + originalPushState.apply(this, arguments); + trackPageview(); + }; + addEventListener("popstate", trackPageview); } - if (event.params) { - const { flags, page } = event.params; - if (Array.isArray(flags)) { - for (const flag of flags) { - props[flag.name] = truncate(flag.value.toString()); + + // 2000 bytes limit + const truncate = (str: string) => `${str}`.slice(0, 990); + + // setup plausible script and unsubscribe + globalThis.window.DECO.events.subscribe((event) => { + if (!event || event.name !== "deco") { + return; + } + if (event.params) { + const { flags, page } = event.params; + if (Array.isArray(flags)) { + for (const flag of flags) { + props[flag.name] = truncate(flag.value.toString()); + } } + props["pageId"] = truncate(`${page.id}`); } - props["pageId"] = truncate(`${page.id}`); - } - trackPageview(); - })(); - globalThis.window.DECO.events.subscribe((event) => { - if (!event) { - return; - } - const { name, params } = event; - if (!name || !params || name === "deco") { - return; - } - const values = { ...props }; - for (const key in params) { - // @ts-expect-error somehow typescript bugs - const value = params[key]; - if (value !== null && value !== undefined) { - values[key] = truncate( - typeof value !== "object" ? value : JSON.stringify(value), - ); + trackPageview(); + })(); + + globalThis.window.DECO.events.subscribe((event) => { + if (!event) { + return; } - } - globalThis.window.plausible?.(name, { props: values }); - }); -}; + const { name, params } = event; + if (!name || !params || name === "deco") { + return; + } + const values = { ...props }; + for (const key in params) { + // @ts-expect-error somehow typescript bugs + const value = params[key]; + if (value !== null && value !== undefined) { + values[key] = truncate( + typeof value !== "object" ? value : JSON.stringify(value), + ); + } + } + globalThis.window.plausible?.(name, { props: values }); + }); + }; +})(); function Component({ exclude, domain }: Props) { return (