chore: Add useGtag hook for recording GA events
This commit is contained in:
Родитель
781803f0d4
Коммит
1b2dfbfc73
|
@ -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.')
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче