analytics/examples/react-spa/use-page-tracking.ts
2026-01-29 08:20:58 -08:00

99 lines
2.3 KiB
TypeScript

/**
* usePageTracking - Automatic page view tracking for React Router
*
* This hook automatically tracks page views when the route changes.
* Place it in your root layout component.
*/
import { useEffect, useRef } from 'react';
import { useLocation } from 'react-router-dom'; // or your router of choice
import { useAnalytics } from '@analytics/client/react';
interface PageTrackingOptions {
/**
* Extract page title from the current route.
* Default: Uses document.title
*/
getPageTitle?: (pathname: string) => string;
/**
* Additional metadata to include with every page view.
*/
metadata?: Record<string, unknown>;
/**
* Skip tracking for certain paths.
*/
excludePaths?: string[];
}
/**
* Track page views automatically on route changes.
*
* @example
* ```tsx
* function RootLayout({ children }) {
* usePageTracking();
* return <main>{children}</main>;
* }
* ```
*/
export function usePageTracking(options: PageTrackingOptions = {}) {
const { trackView } = useAnalytics();
const location = useLocation();
const previousPathRef = useRef<string | null>(null);
const {
getPageTitle = () => document.title,
metadata = {},
excludePaths = [],
} = options;
useEffect(() => {
const currentPath = location.pathname;
// Skip if path is excluded
if (excludePaths.some((path) => currentPath.startsWith(path))) {
return;
}
// Skip if same path (prevents double-tracking on hash changes)
if (previousPathRef.current === currentPath) {
return;
}
previousPathRef.current = currentPath;
// Small delay to ensure document.title is updated
const timeoutId = setTimeout(() => {
trackView({
pageUrl: window.location.href,
pageTitle: getPageTitle(currentPath),
...metadata,
});
}, 0);
return () => clearTimeout(timeoutId);
}, [location.pathname, trackView, getPageTitle, metadata, excludePaths]);
}
/**
* Example with custom page titles:
*
* ```tsx
* const PAGE_TITLES: Record<string, string> = {
* '/': 'Home',
* '/products': 'Products',
* '/about': 'About Us',
* };
*
* function RootLayout({ children }) {
* usePageTracking({
* getPageTitle: (pathname) => PAGE_TITLES[pathname] || 'My App',
* excludePaths: ['/admin', '/api'],
* });
*
* return <main>{children}</main>;
* }
* ```
*/