Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "../globals.css";
import Providers from "../providers";
import Header from "@/components/layout/Header";
import Footer from "@/components/layout/Footer";
import { Analytics } from "@/components/Analytics";

const inter = Inter({ subsets: ["latin"] });

Expand Down Expand Up @@ -112,6 +113,7 @@ export default async function LocaleLayout({
<Footer />
</Providers>
</NextIntlClientProvider>
<Analytics />
</body>
</html>
);
Expand Down
33 changes: 33 additions & 0 deletions src/components/Analytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Script from "next/script";

/**
* Public GA4 measurement ID. Safe to commit — it's exposed in every page's HTML
* anyway. Follows the same hardcoded-default-with-env-override pattern as
* SITE_URL in lib/seo (override per-environment with NEXT_PUBLIC_GA_ID).
*/
const GA_ID = process.env.NEXT_PUBLIC_GA_ID || "G-PPXV98MJ4Y";

/**
* Google Analytics 4, loaded via the Next.js-recommended `afterInteractive`
* strategy. Renders only for real production traffic, so dev and preview builds
* never pollute the analytics data.
*/
export function Analytics() {
if (process.env.NODE_ENV !== "production" || !GA_ID) return null;

const gaId = GA_ID;
return (
<>
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${gaId}`}
strategy="afterInteractive"
/>
<Script id="ga4-init" strategy="afterInteractive">
{`window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${gaId}');`}
</Script>
</>
);
}
Loading