xref: /expo/docs/providers/Analytics.tsx (revision 06541964)
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