From 6ddbe7d377a2f64b97edacfa71f1020b871850d7 Mon Sep 17 00:00:00 2001
From: Zonghao Yuan <64521992+zonghaoyuan@users.noreply.github.com>
Date: Wed, 3 Jun 2026 01:14:55 +0800
Subject: [PATCH] feat: add privacy-friendly Umami page-view analytics (#15)
Cookieless, env-gated page-view tracking via Umami. The
component injects the script only when NEXT_PUBLIC_UMAMI_SRC and
NEXT_PUBLIC_UMAMI_WEBSITE_ID are both set, so local dev and forks send
nothing to our instance. Adds .env.example docs (section 6) and a
homepage footer privacy disclosure. No Cookie consent banner needed.
---
.env.example | 12 ++++++++++++
app/layout.tsx | 2 ++
app/page.tsx | 2 ++
components/Analytics.tsx | 18 ++++++++++++++++++
4 files changed, 34 insertions(+)
create mode 100644 components/Analytics.tsx
diff --git a/.env.example b/.env.example
index 5aca3df..aac003d 100644
--- a/.env.example
+++ b/.env.example
@@ -55,3 +55,15 @@ TTS_SPEECH_MODEL=mimo-v2.5-tts
# true → return a placeholder image instead of calling the image model.
# Text/story/voice still run normally. Great for iterating on TTS.
MOCK_IMAGE=false
+
+# ---- 6. Analytics · Umami (optional — leave blank to disable) ------
+# Privacy-friendly, cookieless page-view stats — no Cookie consent banner.
+# Cloud: sign up at https://cloud.umami.is, add your site, copy its ID into
+# NEXT_PUBLIC_UMAMI_WEBSITE_ID and use the cloud script URL:
+# NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
+# Self-host later: point SRC at your own instance — the integration is identical
+# (no code change), e.g. NEXT_PUBLIC_UMAMI_SRC=https://stats.example.com/script.js
+# Both blank → no script is injected (zero tracking). NEXT_PUBLIC_ vars are
+# inlined at BUILD time, so set them in the build env (Vercel project settings).
+NEXT_PUBLIC_UMAMI_SRC=
+NEXT_PUBLIC_UMAMI_WEBSITE_ID=
diff --git a/app/layout.tsx b/app/layout.tsx
index bf87079..ec8a719 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import { Cormorant_Garamond, Inter } from "next/font/google";
+import { Analytics } from "@/components/Analytics";
import "./globals.css";
// Editorial fonts: drive tailwind `font-serif`/`font-sans` via
@@ -44,6 +45,7 @@ export default function RootLayout({
{children}
+