chore: Add useGtag hook for recording GA events

This commit is contained in:
Florian Zia 2023-09-21 15:09:11 +02:00
Родитель 781803f0d4
Коммит 1b2dfbfc73
Не найден ключ, соответствующий данной подписи
11 изменённых файлов: 157 добавлений и 55 удалений

Просмотреть файл

@ -126,7 +126,7 @@ ADMINS=
# Enable monthly cron-job, currently for sending unresolved breach reminder emails
MONTHLY_CRON_ENABLED=
GA4_MEASUREMENT_ID=test
NEXT_PUBLIC_GA4_MEASUREMENT_ID=test
# E2E Tests
E2E_TEST_ENV=

Просмотреть файл

@ -36,7 +36,7 @@ esbuild.build({
define: {
buildConstants: JSON.stringify({
NODE_ENV: AppConstants.NODE_ENV,
GA4_MEASUREMENT_ID: AppConstants.GA4_MEASUREMENT_ID
NEXT_PUBLIC_GA4_MEASUREMENT_ID: AppConstants.NEXT_PUBLIC_GA4_MEASUREMENT_ID
})
}
})

Просмотреть файл

@ -6,7 +6,7 @@
import { useEffect } from "react";
import { usePathname } from "next/navigation";
import { useGlean } from "../../../hooks/useGlean";
import { useGlean } from "../../../hooks/useAnalytics";
import { useCookies } from "react-cookie";
export type Props = {

Просмотреть файл

@ -3,15 +3,25 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { ReactNode } from "react";
import Script from "next/script";
import { getL10nBundles, getLocale } from "../functions/server/l10n";
import { L10nProvider } from "../../contextProviders/localization";
import { ReactAriaI18nProvider } from "../../contextProviders/react-aria";
import { getNonce } from "../functions/server/getNonce";
export default function Layout({ children }: { children: ReactNode }) {
const l10nBundles = getL10nBundles();
const ga4MeasurementId =
process.env.NEXT_PUBLIC_NEXT_PUBLIC_GA4_MEASUREMENT_ID || "G-CXG8K4KW4P";
const nonce = getNonce() || "";
return (
<L10nProvider bundleSources={l10nBundles}>
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${ga4MeasurementId}`}
nonce={nonce}
/>
<ReactAriaI18nProvider locale={getLocale(l10nBundles)}>
{children}
</ReactAriaI18nProvider>

Просмотреть файл

@ -0,0 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { headers } from "next/headers";
export function getNonce() {
// This header gets set in /src/middleware.ts:
const nonce = headers().get("x-nonce") ?? undefined;
return nonce;
}

Просмотреть файл

@ -0,0 +1,128 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use client";
import { useEffect } from "react";
import Glean from "@mozilla/glean/web";
import * as pageEvents from "../../telemetry/generated/page";
// Custom hook that initializes Glean and returns the Glean objects required
// to record data.
export const useGlean = () => {
// Initialize Glean only on the first render
// of our custom hook.
useEffect(() => {
// Enable upload only if the user opted into tracking.
const uploadEnabled = navigator.doNotTrack === "0";
const channel = process.env.NEXT_PUBLIC_APP_ENV;
if (!channel) {
console.warn("No channel defined in env var NEXT_PUBLIC_APP_ENV");
}
Glean.initialize("monitor.frontend", uploadEnabled, {
// This will submit an events ping every time an event is recorded.
maxEvents: 1,
channel,
});
// Glean debugging options can be found here:
// https://mozilla.github.io/glean/book/reference/debug/index.html
const appEnv = process.env.NEXT_PUBLIC_APP_ENV;
if (appEnv && ["local", "heroku"].includes(appEnv)) {
// Enable logging pings to the browser console.
Glean.setLogPings(true);
// Tag pings for the Debug Viewer
// @see https://debug-ping-preview.firebaseapp.com/pings/fx-monitor-local-dev
Glean.setDebugViewTag(`fx-monitor-${appEnv}-dev`);
}
}, []);
// Return all generated Glean objects required for recording data.
return {
pageEvents,
};
};
declare global {
interface Window {
dataLayer: unknown[];
}
}
interface InitGaProps {
ga4MeasurementId: string;
debugMode: boolean;
}
export const initGa4 = ({ ga4MeasurementId, debugMode }: InitGaProps) => {
if (typeof window === undefined) {
return;
}
if (debugMode) {
console.info("Initialize GA4");
}
const uploadEnabled = navigator.doNotTrack !== "0";
if (!uploadEnabled) {
if (debugMode) {
console.info("Cound not initialize GA4 due to DNT.");
}
return;
}
// GA4 setup
window.dataLayer = window.dataLayer || [];
if (!window.gtag) {
window.gtag = function (...args: unknown[]) {
window.dataLayer.push(args);
};
window.gtag("js", new Date());
window.gtag("config", ga4MeasurementId, {
cookie_domain: window.location.hostname,
cookie_flags: "SameSite=None;Secure",
debug_mode: debugMode,
});
}
};
type Ga4EventOptions = {
type: "event";
name: string;
params: object;
};
export const useGtag = (): {
gtag: {
record: (options: Ga4EventOptions) => void;
};
} => {
const debugMode = process.env.NEXT_PUBLIC_NODE_ENV !== "production";
useEffect(() => {
if (!window.gtag) {
if (process.env.NEXT_PUBLIC_NODE_ENV !== "production") {
console.warn("GA4 is not initialized.");
}
const ga4MeasurementId =
process.env.NEXT_PUBLIC_NEXT_PUBLIC_GA4_MEASUREMENT_ID ||
"G-CXG8K4KW4P";
initGa4({ ga4MeasurementId, debugMode });
}
}, [debugMode]);
return {
gtag: {
record: (options) => {
if (window.gtag) {
window.gtag(options);
} else if (!window.gtag && debugMode) {
console.warn("Could not find gtag.");
}
},
},
};
};

Просмотреть файл

@ -1,47 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use client";
import { useEffect } from "react";
import Glean from "@mozilla/glean/web";
import * as pageEvents from "../../telemetry/generated/page";
// Custom hook that initializes Glean and returns the Glean objects required
// to record data.
export const useGlean = () => {
// Initialize Glean only on the first render
// of our custom hook.
useEffect(() => {
// Enable upload only if the user has not opted out of tracking.
const uploadEnabled = navigator.doNotTrack !== "1";
const channel = process.env.NEXT_PUBLIC_APP_ENV;
if (!channel) {
console.warn("No channel defined in env var NEXT_PUBLIC_APP_ENV");
}
Glean.initialize("monitor.frontend", uploadEnabled, {
// This will submit an events ping every time an event is recorded.
maxEvents: 1,
channel,
});
// Glean debugging options can be found here:
// https://mozilla.github.io/glean/book/reference/debug/index.html
const appEnv = process.env.NEXT_PUBLIC_APP_ENV;
if (appEnv && ["local", "heroku"].includes(appEnv)) {
// Enable logging pings to the browser console.
Glean.setLogPings(true);
// Tag pings for the Debug Viewer
// @see https://debug-ping-preview.firebaseapp.com/pings/fx-monitor-local-dev
Glean.setDebugViewTag(`fx-monitor-${appEnv}-dev`);
}
}, []);
// Return all generated Glean objects required for recording data.
return {
pageEvents,
};
};

Просмотреть файл

@ -54,7 +54,7 @@ export default async function RootLayout({
className={`${inter.className} ${inter.variable} ${metropolis.variable}`}
// DO NOT ADD SECRETS HERE: The following data attributes expose
// variables that are being used in the public analytics scripts
data-ga4-measurement-id={process.env.GA4_MEASUREMENT_ID}
data-ga4-measurement-id={process.env.NEXT_PUBLIC_GA4_MEASUREMENT_ID}
data-node-env={process.env.NODE_ENV}
>
<SessionProvider session={session}>{children}</SessionProvider>

Просмотреть файл

@ -54,7 +54,7 @@ const optionalEnvVars = [
'FX_REMOTE_SETTINGS_WRITER_SERVER',
'FX_REMOTE_SETTINGS_WRITER_USER',
'GA4_DEBUG_MODE',
'GA4_MEASUREMENT_ID',
'NEXT_PUBLIC_GA4_MEASUREMENT_ID',
'HIBP_BREACH_DOMAIN_BLOCKLIST',
'LIVE_RELOAD',
'PORT',

Просмотреть файл

@ -12,7 +12,7 @@ if (navigator.doNotTrack === '1') {
}
window.gtag()
} else {
await import(`https://www.googletagmanager.com/gtag/js?id=${AppConstants.GA4_MEASUREMENT_ID}`)
await import(`https://www.googletagmanager.com/gtag/js?id=${AppConstants.NEXT_PUBLIC_GA4_MEASUREMENT_ID}`)
window.dataLayer = window.dataLayer || []
@ -20,7 +20,7 @@ if (navigator.doNotTrack === '1') {
window.dataLayer.push(arguments)
}
window.gtag('js', new Date())
window.gtag('config', AppConstants.GA4_MEASUREMENT_ID, {
window.gtag('config', AppConstants.NEXT_PUBLIC_GA4_MEASUREMENT_ID, {
cookie_domain: window.location.hostname,
cookie_flags: 'SameSite=None;Secure',
debug_mode: debugMode

Просмотреть файл

@ -20,7 +20,7 @@ if (typeof buildConstants === 'object') {
} else {
// Build-phase was not run (npm run dev). Assign fallbacks for testing if needed.
Object.assign(AppConstants, {
GA4_MEASUREMENT_ID: 'G-CXG8K4KW4P'
NEXT_PUBLIC_GA4_MEASUREMENT_ID: 'G-CXG8K4KW4P'
})
console.log('Running dev-mode with fallback values for AppConstants.')
}