From 5fd3b3b542562dfc6f9e9e7c5340b01a81024146 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 23 Sep 2025 07:48:55 +0200 Subject: [PATCH 1/2] fix umami analytics --- .vscode/settings.json | 5 +++ apps/web/src/analytics.ts | 33 ----------------- apps/web/src/components/Layout.tsx | 5 --- apps/web/src/main.tsx | 3 +- apps/web/src/utils/umami.ts | 43 ++++++++++++++++++++++ apps/web/src/utils/umamiPageViewTracker.ts | 16 ++++++++ 6 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 apps/web/src/analytics.ts create mode 100644 apps/web/src/utils/umami.ts create mode 100644 apps/web/src/utils/umamiPageViewTracker.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..0b3dae468 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "dev" + ] +} \ No newline at end of file diff --git a/apps/web/src/analytics.ts b/apps/web/src/analytics.ts deleted file mode 100644 index a3e9cf8bd..000000000 --- a/apps/web/src/analytics.ts +++ /dev/null @@ -1,33 +0,0 @@ -declare global { - interface Window { - umami?: { - track: (eventName?: string, data?: Record) => void; - trackView: (url?: string, referrer?: string | null, websiteId?: string) => void; - }; - } -} - -// Prevent duplicate for same route -let lastPathname: string | null = null; - -// Wait for Umami script -function whenUmamiReady(cb: () => void, tries = 20) { - if (typeof window !== "undefined" && window.umami) return cb(); - if (tries <= 0) return; - setTimeout(() => whenUmamiReady(cb, tries - 1), 250); -} - -const WEBSITE_ID = "13760d0b-e30d-43c2-9026-1920a86720c8"; - -export function trackPageView(pathname: string) { - if (!pathname || pathname === lastPathname) return; - lastPathname = pathname; - - whenUmamiReady(() => { - if (window.umami?.trackView) { - window.umami.trackView(pathname, document.referrer || null, WEBSITE_ID); - } else if (window.umami?.track) { - window.umami.track("pageview", { url: pathname, website: WEBSITE_ID }); - } - }); -} diff --git a/apps/web/src/components/Layout.tsx b/apps/web/src/components/Layout.tsx index a7d3d80df..dea5a7a3a 100644 --- a/apps/web/src/components/Layout.tsx +++ b/apps/web/src/components/Layout.tsx @@ -2,7 +2,6 @@ import { NavLink, Outlet, useLocation } from "react-router-dom"; import { useEffect, useState, useRef } from "react"; import styles from "../styles/Layout.module.css"; import { ConnectButton } from "./ConnectButton" -import { trackPageView } from "../analytics"; export default function Layout() { const location = useLocation(); @@ -19,10 +18,6 @@ export default function Layout() { } }, [location]); - useEffect(() => { - trackPageView(location.pathname); - }, [location]); - return (
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index 91bf97e00..3070ec016 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -6,13 +6,14 @@ import { RootProviders } from "./lib/dynamic" import { LiveRefetchProvider } from "./live/LiveRefetchProvider"; import { AlertsProvider, AlertToaster, AlertModalHost } from "./features/alerts/Alerts"; import styles from "../../web/src/styles/Layout.module.css" - +import PageViewTracker from "./utils/umamiPageViewTracker"; ReactDOM.createRoot(document.getElementById("root")!).render( +
diff --git a/apps/web/src/utils/umami.ts b/apps/web/src/utils/umami.ts new file mode 100644 index 000000000..7dc27af20 --- /dev/null +++ b/apps/web/src/utils/umami.ts @@ -0,0 +1,43 @@ +export async function trackEvent(eventName, url, props = {}) { + const origin = import.meta.env.VITE_UMAMI_API_ORIGIN; + const websiteId = import.meta.env.VITE_UMAMI_API_CLIENT_USER_ID; + const apiKey = import.meta.env.VITE_UMAMI_CLIENT_SECRET; + + const response = await fetch("https://api.ipify.org?format=json") + const apifyResponse = await response.json() + + if (!origin || !websiteId) { + console.error("Umami origin or website ID missing"); + return; + } + + const body = { + type: "event", + payload: { + name: eventName, + website: websiteId, + url, + ip: apifyResponse.ip, + props, + }, + }; + + try { + const res = await fetch(`${origin}/api/send`, { + method: "POST", + headers: { + "Content-Type": "application/json", + ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}), + }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + console.error("[Umami] Error", res.status, await res.text()); + } else { + console.log("[Umami] Success", res.status); + } + } catch (e) { + console.error("[Umami] Fetch failed:", e); + } +} \ No newline at end of file diff --git a/apps/web/src/utils/umamiPageViewTracker.ts b/apps/web/src/utils/umamiPageViewTracker.ts new file mode 100644 index 000000000..447888858 --- /dev/null +++ b/apps/web/src/utils/umamiPageViewTracker.ts @@ -0,0 +1,16 @@ +import { useEffect } from "react" +import { useLocation } from "react-router-dom" +import { trackEvent } from "./umami" + +const PageViewTracker = () => { + const location = useLocation() + + useEffect(() => { + // Track page view whenever location changes + trackEvent("page_view", location.pathname, { path: location.pathname }) + }, [location]) + + return null // This component doesn't render anything +} + +export default PageViewTracker From 18e9502a7bd7f4e761b6832b52244c89bf7ffb94 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 23 Sep 2025 09:39:01 +0200 Subject: [PATCH 2/2] fix umami analytics --- apps/web/index.html | 10 +---- apps/web/src/main.tsx | 2 - apps/web/src/utils/umami.ts | 43 ---------------------- apps/web/src/utils/umamiPageViewTracker.ts | 16 -------- 4 files changed, 1 insertion(+), 70 deletions(-) delete mode 100644 apps/web/src/utils/umami.ts delete mode 100644 apps/web/src/utils/umamiPageViewTracker.ts diff --git a/apps/web/index.html b/apps/web/index.html index 27385b378..9c0c85b40 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -4,15 +4,7 @@ TrustSwap - +