Skip to content
This repository has been archived by the owner on Jan 8, 2025. It is now read-only.

Add GA4 Tracking events #457

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
9 changes: 9 additions & 0 deletions components/Link/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import NextLink, { LinkProps as NextLinkProps } from "next/link";
import { isHash, isExternalLink, isLocalAssetFile } from "utils/url";
import { useNormalizedHref } from "./hooks";
import styles from "./Link.module.css";
import { TrackingEvent } from "utils/tracking";

export interface LinkProps extends Omit<NextLinkProps, "href"> {
passthrough?: boolean;
Expand All @@ -25,6 +26,7 @@ const Link = ({
prefetch,
locale,
scheme,
onClick,
...linkProps
}: LinkProps) => {
const normalizedHref = useNormalizedHref(href);
Expand Down Expand Up @@ -74,6 +76,13 @@ const Link = ({
<NextLink
{...nextProps}
prefetch={false}
onClick={(e) => {
TrackingEvent("internal_link_click", {
title: e.currentTarget.firstChild.nodeValue || "",
href: href,
});
onClick && onClick(e);
}}
className={cn(styles.wrapper, styles[scheme], className)}
>
{children}
Expand Down
68 changes: 62 additions & 6 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import Script from "next/script";
import type { AppProps } from "next/app";
import { DocsContextProvider } from "layouts/DocsPage/context";
import { posthog, sendPageview } from "utils/posthog";
import { posthog, sendEngagedView, sendPageview } from "utils/posthog";
import { TabContextProvider } from "components/Tabs";

// https://larsmagnus.co/blog/how-to-optimize-custom-fonts-with-next-font
Expand Down Expand Up @@ -54,6 +54,7 @@ export const lato = localLato({

import "styles/varaibles.css";
import "styles/global.css";
import { TrackingEvent } from "utils/tracking";

const NEXT_PUBLIC_REDDIT_ID = process.env.NEXT_PUBLIC_REDDIT_ID;
const NEXT_PUBLIC_GTM_ID = process.env.NEXT_PUBLIC_GTM_ID;
Expand All @@ -68,7 +69,32 @@ interface dataLayerItem {
declare global {
var dataLayer: dataLayerItem[]; // eslint-disable-line no-var
}
const useIsEngaged = () => {
const router = useRouter();
const [timerReached, setTimerReached] = useState(false);
const [secondPageReached, setSecondPageReached] = useState(false);
const [isEngaged, setIsEngaged] = useState(false);

useEffect(() => {
setTimeout(() => {
setTimerReached(true);
}, 30000);
const routeChanged = () => {
setSecondPageReached(true);
};

router.events.on("routeChangeComplete", routeChanged);
return () => {
router.events.off("routeChangeComplete", routeChanged);
};
}, [router.events]);

useEffect(() => {
setIsEngaged(secondPageReached && timerReached);
}, [secondPageReached, timerReached]);

return isEngaged;
};
const Analytics = () => {
return (
<>
Expand Down Expand Up @@ -163,6 +189,18 @@ const Analytics = () => {
{/* End Google Tag Manager (noscript) */}
</>
)}
{/* Quailified Script */}
<Script id="script_qualified">
{`(function (w, q) {
w["QualifiedObject"] = q;
w[q] =
w[q] ||
function () {
(w[q].q = w[q].q || []).push(arguments);
};
})(window, "qualified")`}
</Script>
<Script src="https://js.qualified.com/qualified.js?token=GWPbwWJLtjykim4W" />

{NEXT_PUBLIC_REDDIT_ID && (
<>
Expand All @@ -180,14 +218,32 @@ const Analytics = () => {

const MyApp = ({ Component, pageProps }: AppProps) => {
const router = useRouter();
const isEngaged = useIsEngaged();

useEffect(() => {
posthog(); // init posthog

router.events.on("routeChangeComplete", sendPageview);
if (!isEngaged) return;
// Trigger engagement view events here
sendEngagedView();
TrackingEvent("session_threshold", {
session_threshold_reached: 30,
});
}, [isEngaged]);

const Pageviews = () => {
// Trigger page views here
TrackingEvent("page_view");
// Qualified page view
if (!!window["qualified"]) window["qualified"]("page");
// Posthog page view
sendPageview();
};
useEffect(() => {
posthog(); // init posthog
// Trigger initial load page views
Pageviews();
router.events.on("routeChangeComplete", Pageviews);
return () => {
router.events.off("routeChangeComplete", sendPageview);
router.events.off("routeChangeComplete", Pageviews);
};
}, [router.events]);

Expand Down
8 changes: 8 additions & 0 deletions utils/posthog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,11 @@ export const sendDocsFeedback = async (rating: string, comment: string) => {
"web.docs.comment": comment,
});
};

export const sendEngagedView = async () => {
const ph = await posthog();
ph?.capture("web.engagement.timer", {
"web.engagement.sessionTimerThreshold": 30,
"web.engagement.sessionPageThreshold": 2,
});
};
22 changes: 22 additions & 0 deletions utils/tracking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* GTAG GA4 Events */

export const isGtagEnabled = () =>
typeof window !== "undefined" && !!window.dataLayer;

// Wraepper around GA4 tracking calls to prevent errors when used locally

export const TrackingEvent = (
event: string,
payload: Record<string, unknown> = {}
) => {
return new Promise<void>((resolve) => {
if (isGtagEnabled()) {
window.gtag("event", event, {
...payload,
});
} else {
console.log("GA4 Tracking Event", payload);
resolve();
}
});
};
Loading