1import { NextWebVitalsMetric } from 'next/app'; 2import { useRouter } from 'next/compat/router'; 3import Script from 'next/script'; 4import React, { PropsWithChildren, useEffect } from 'react'; 5 6/** The global analytics measurement ID */ 7const MEASUREMENT_ID = 'G-YKNPYCMLWY'; 8 9type AnalyticsProps = PropsWithChildren<object>; 10 11/** 12 * @see https://nextjs.org/docs/messages/next-script-for-ga 13 * @see https://nextjs.org/docs/basic-features/script#lazyonload 14 */ 15export function AnalyticsProvider(props: AnalyticsProps) { 16 const router = useRouter(); 17 18 useEffect(function didMount() { 19 router?.events.on('routeChangeComplete', reportPageView); 20 return function didUnmount() { 21 router?.events.off('routeChangeComplete', reportPageView); 22 }; 23 }, []); 24 25 return ( 26 <> 27 <Script 28 id="gtm-script" 29 strategy="lazyOnload" 30 src={`https://www.googletagmanager.com/gtag/js?id=${MEASUREMENT_ID}`} 31 /> 32 <Script id="gtm-init" strategy="lazyOnload">{` 33 window.dataLayer = window.dataLayer || []; 34 function gtag(){dataLayer.push(arguments);} 35 gtag('js', new Date()); 36 gtag('config', '${MEASUREMENT_ID}', { 'transport_type': 'beacon', 'anonymize_ip': true }); 37 `}</Script> 38 {props.children} 39 </> 40 ); 41} 42 43export function reportPageView(url: string) { 44 window?.gtag?.('config', MEASUREMENT_ID, { 45 page_path: url, 46 transport_type: 'beacon', 47 anonymize_ip: true, 48 }); 49} 50 51export function reportWebVitals({ id, name, label, value }: NextWebVitalsMetric) { 52 window?.gtag?.('event', name, { 53 event_category: label === 'web-vital' ? 'Web Vitals' : 'Next.js custom metric', 54 // Google Analytics metrics must be integers, so the value is rounded. 55 // For CLS the value is first multiplied by 1000 for greater precision 56 // (note: increase the multiplier for greater precision if needed). 57 value: Math.round(name === 'CLS' ? value * 1000 : value), 58 // The `id` value will be unique to the current page load. When sending 59 // multiple values from the same page (e.g. for CLS), Google Analytics can 60 // compute a total by grouping on this ID (note: requires `eventLabel` to 61 // be a dimension in your report). 62 event_label: id, 63 // Use a non-interaction event to avoid affecting bounce rate. 64 non_interaction: true, 65 anonymize_ip: true, 66 }); 67} 68 69export function reportPageVote({ status }: { status: boolean }) { 70 window?.gtag?.('event', status ? 'page_vote_up' : 'page_vote_down', { 71 event_category: 'Page vote', 72 value: window?.location.pathname, 73 // Use a non-interaction event to avoid affecting bounce rate. 74 non_interaction: true, 75 anonymize_ip: true, 76 }); 77} 78