diff --git a/packages/fern-docs/bundle/src/pages/404.tsx b/packages/fern-docs/bundle/src/pages/404.tsx index 336c1f2f5b..4c21ddd497 100644 --- a/packages/fern-docs/bundle/src/pages/404.tsx +++ b/packages/fern-docs/bundle/src/pages/404.tsx @@ -1,4 +1,4 @@ -import { capturePosthogEvent } from "@fern-docs/ui"; +import { track } from "@fern-docs/ui"; import Error from "next/error"; import { ReactElement, useEffect } from "react"; @@ -12,7 +12,7 @@ import { ReactElement, useEffect } from "react"; // If you use initial props, the middleware's response will probably cause a client-side error to be thrown. export default function Page(): ReactElement { useEffect(() => { - capturePosthogEvent("not_found"); + track("not_found"); }); return ; diff --git a/packages/fern-docs/ui/package.json b/packages/fern-docs/ui/package.json index 7f7a7441b4..990103d372 100644 --- a/packages/fern-docs/ui/package.json +++ b/packages/fern-docs/ui/package.json @@ -59,7 +59,6 @@ "@fern-ui/loadable": "workspace:*", "@fern-ui/react-commons": "workspace:*", "@inkeep/widgets": "^0.2.288", - "@next/third-parties": "14.2.9", "@radix-ui/colors": "^3.0.0", "@radix-ui/react-accordion": "^1.2.1", "@radix-ui/react-collapsible": "^1.1.1", diff --git a/packages/fern-docs/ui/src/analytics/CustomerAnalytics.tsx b/packages/fern-docs/ui/src/analytics/CustomerAnalytics.tsx index 2280826221..e11b88ea11 100644 --- a/packages/fern-docs/ui/src/analytics/CustomerAnalytics.tsx +++ b/packages/fern-docs/ui/src/analytics/CustomerAnalytics.tsx @@ -20,12 +20,8 @@ const IntercomScript = dynamic(() => const FullstoryScript = dynamic(() => import("./FullstoryScript").then((mod) => mod.FullstoryScript) ); -const GoogleAnalytics = dynamic(() => - import("@next/third-parties/google").then((mod) => mod.GoogleAnalytics) -); -const GoogleTagManager = dynamic(() => - import("@next/third-parties/google").then((mod) => mod.GoogleTagManager) -); +const GoogleAnalytics = dynamic(() => import("./ga"), { ssr: true }); +const GoogleTagManager = dynamic(() => import("./gtm"), { ssr: true }); const ANALYTICS_ATOM = selectAtom( DOCS_ATOM, @@ -57,7 +53,7 @@ export const CustomerAnalytics = memo( - {/* renders Google Analytics 4 or Google Tag Manager using @next/third-parties */} + {/* renders Google Analytics 4 or Google Tag Manager */} {ga4 != null && } {gtm != null && } diff --git a/packages/fern-docs/ui/src/analytics/PosthogContainer.tsx b/packages/fern-docs/ui/src/analytics/PosthogContainer.tsx index 0655f4a3be..8a0ea9903b 100644 --- a/packages/fern-docs/ui/src/analytics/PosthogContainer.tsx +++ b/packages/fern-docs/ui/src/analytics/PosthogContainer.tsx @@ -1,10 +1,21 @@ import { DocsV1Read } from "@fern-api/fdr-sdk"; import { ReactElement } from "react"; -import { useInitializePosthog } from "./posthog"; +import { + capturePosthogEventCustomer, + capturePosthogEventInternal, + useInitializePosthog, +} from "./posthog"; +import { useSafeListenTrackEvents } from "./use-track"; export function Posthog(props: { customerConfig?: DocsV1Read.PostHogConfig; }): ReactElement { useInitializePosthog(props.customerConfig); + useSafeListenTrackEvents(({ event, properties }) => { + capturePosthogEventCustomer(event, properties); + }); + useSafeListenTrackEvents(({ event, properties }) => { + capturePosthogEventInternal(event, properties); + }, true); return <>; } diff --git a/packages/fern-docs/ui/src/analytics/constants.ts b/packages/fern-docs/ui/src/analytics/constants.ts new file mode 100644 index 0000000000..b1a18bcccc --- /dev/null +++ b/packages/fern-docs/ui/src/analytics/constants.ts @@ -0,0 +1 @@ +export const TRACK_EVENT_NAME = "fern-docs-track-analytics"; diff --git a/packages/fern-docs/ui/src/analytics/ga.tsx b/packages/fern-docs/ui/src/analytics/ga.tsx new file mode 100644 index 0000000000..679ff5e591 --- /dev/null +++ b/packages/fern-docs/ui/src/analytics/ga.tsx @@ -0,0 +1,70 @@ +import Head from "next/head"; +import Script from "next/script"; +import { ReactNode, useEffect } from "react"; +import { useSafeListenTrackEvents } from "./use-track"; + +declare global { + // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style + interface Window { + [key: string]: any; + } +} + +type GAParams = { + gaId: string; + dataLayerName?: string; + debugMode?: boolean; + nonce?: string; +}; + +export default function GoogleAnalytics(props: GAParams): ReactNode { + const { gaId, debugMode, dataLayerName = "dataLayer", nonce } = props; + useEffect(() => { + // performance.mark is being used as a feature use signal. While it is traditionally used for performance + // benchmarking it is low overhead and thus considered safe to use in production and it is a widely available + // existing API. + // The performance measurement will be handled by Chrome Aurora + + performance.mark("mark_feature_usage", { + detail: { + feature: "fern-analytics-ga", + }, + }); + }, []); + + useSafeListenTrackEvents(({ event, properties }) => { + sendGAEvent(dataLayerName, { event, properties }); + }); + + return ( + <> + +