Analytics Hooks
The @54vie/analytics package provides several React hooks for integrating analytics into your components. These hooks provide type-safe access to analytics functionality throughout your application.
useAnalytics
The primary hook for tracking events and managing user identity.
Import
import { useAnalytics } from '@54vie/analytics';
Return Type
interface UseAnalyticsReturn {
/**
* Track a custom event with optional properties
*/
track: (eventName: string, properties?: EventProperties) => void;
/**
* Track a standard event from the StandardEvents enum
*/
trackStandard: (event: StandardEvents, properties?: EventProperties) => void;
/**
* Identify a user with optional traits
*/
identify: (userId: string, traits?: UserTraits) => void;
/**
* Alias a user ID to another
*/
alias: (newId: string, originalId?: string) => void;
/**
* Reset user identity and start a new anonymous session
*/
reset: () => void;
/**
* Manually flush queued events to the server
*/
flush: () => Promise<void>;
/**
* Check if analytics is initialized and ready
*/
isReady: boolean;
/**
* Check if user has opted out of tracking
*/
isOptedOut: boolean;
/**
* Opt out of analytics tracking
*/
optOut: () => void;
/**
* Opt back into analytics tracking
*/
optIn: () => void;
/**
* Get the current anonymous ID
*/
anonymousId: string | null;
/**
* Get the current user ID
*/
userId: string | null;
/**
* Get the current session ID
*/
sessionId: string | null;
}
type EventProperties = Record<string, string | number | boolean | null | undefined | string[] | number[]>;
interface UserTraits {
email?: string;
name?: string;
firstName?: string;
lastName?: string;
phone?: string;
createdAt?: string | Date;
plan?: string;
[key: string]: unknown;
}
Usage Examples
import { useAnalytics, StandardEvents } from '@54vie/analytics';
function ProductPage({ product }) {
const { track, trackStandard, isReady } = useAnalytics();
useEffect(() => {
if (isReady) {
trackStandard(StandardEvents.PAGE_VIEW, {
page: 'product',
productId: product.id,
});
}
}, [isReady, product.id]);
const handleAddToCart = () => {
track('add_to_cart', {
productId: product.id,
productName: product.name,
price: product.price,
currency: 'USD',
quantity: 1,
});
};
return (
<button onClick={handleAddToCart}>
Add to Cart
</button>
);
}
User Identification
import { useAnalytics } from '@54vie/analytics';
function LoginForm() {
const { identify } = useAnalytics();
const handleLogin = async (credentials) => {
const user = await loginUser(credentials);
identify(user.id, {
email: user.email,
name: user.name,
plan: user.subscription.plan,
createdAt: user.createdAt,
});
};
return <form onSubmit={handleLogin}>{/* form fields */}</form>;
}
Handling Logout
import { useAnalytics } from '@54vie/analytics';
function LogoutButton() {
const { reset, flush } = useAnalytics();
const handleLogout = async () => {
// Flush any pending events before reset
await flush();
// Reset clears user identity and starts new anonymous session
reset();
// Proceed with logout
await logoutUser();
};
return <button onClick={handleLogout}>Logout</button>;
}
useUserProperties
Hook for managing user properties and traits that persist across sessions.
Import
import { useUserProperties } from '@54vie/analytics';
Return Type
interface UseUserPropertiesReturn {
/**
* Set one or more user properties
* Properties are merged with existing properties
*/
setProperties: (properties: UserProperties) => void;
/**
* Set a single user property
*/
setProperty: (key: string, value: PropertyValue) => void;
/**
* Increment a numeric property
*/
increment: (key: string, amount?: number) => void;
/**
* Append to an array property
*/
append: (key: string, value: PropertyValue) => void;
/**
* Remove from an array property
*/
remove: (key: string, value: PropertyValue) => void;
/**
* Set a property only if it hasn't been set before
*/
setOnce: (key: string, value: PropertyValue) => void;
/**
* Unset (remove) a user property
*/
unset: (key: string) => void;
/**
* Get all current user properties
*/
properties: UserProperties;
/**
* Check if properties are loading
*/
isLoading: boolean;
}
type PropertyValue = string | number | boolean | null | string[] | number[];
interface UserProperties {
[key: string]: PropertyValue;
}
Usage Examples
import { useUserProperties } from '@54vie/analytics';
function OnboardingFlow() {
const { setProperties, setOnce, increment } = useUserProperties();
const completeStep = (stepName: string) => {
// Track onboarding progress
setProperties({
onboardingStep: stepName,
lastActiveAt: new Date().toISOString(),
});
// Increment completed steps count
increment('completedSteps');
};
const setInitialProperties = () => {
// Only set if not already set
setOnce('firstVisitAt', new Date().toISOString());
setOnce('signupSource', 'organic');
};
return (
<div>
<button onClick={() => completeStep('profile')}>
Complete Profile
</button>
</div>
);
}
Managing Preferences
import { useUserProperties } from '@54vie/analytics';
function PreferencesForm() {
const { setProperty, properties, isLoading } = useUserProperties();
if (isLoading) {
return <LoadingSpinner />;
}
return (
<form>
<label>
<input
type="checkbox"
checked={properties.emailNotifications as boolean}
onChange={(e) => setProperty('emailNotifications', e.target.checked)}
/>
Email Notifications
</label>
<select
value={properties.theme as string}
onChange={(e) => setProperty('theme', e.target.value)}
>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="system">System</option>
</select>
</form>
);
}
Working with Arrays
import { useUserProperties } from '@54vie/analytics';
function InterestsSelector() {
const { append, remove, properties } = useUserProperties();
const interests = (properties.interests as string[]) || [];
const toggleInterest = (interest: string) => {
if (interests.includes(interest)) {
remove('interests', interest);
} else {
append('interests', interest);
}
};
return (
<div>
{['Technology', 'Design', 'Business', 'Marketing'].map((interest) => (
<button
key={interest}
onClick={() => toggleInterest(interest)}
className={interests.includes(interest) ? 'selected' : ''}
>
{interest}
</button>
))}
</div>
);
}
useExperiment
Hook for accessing A/B test variants and tracking experiment participation.
Import
import { useExperiment } from '@54vie/analytics';
Return Type
interface UseExperimentReturn<T = string> {
/**
* The assigned variant for this experiment
*/
variant: T;
/**
* Whether the experiment data is still loading
*/
isLoading: boolean;
/**
* Whether the experiment is active
*/
isActive: boolean;
/**
* Error if experiment fetch failed
*/
error: Error | null;
/**
* Track a conversion event for this experiment
*/
trackConversion: (conversionName?: string, properties?: EventProperties) => void;
/**
* Track exposure to this experiment variant
* Called automatically when variant is accessed
*/
trackExposure: () => void;
/**
* Get experiment metadata
*/
metadata: ExperimentMetadata | null;
}
interface ExperimentMetadata {
experimentId: string;
experimentName: string;
variantId: string;
variantName: string;
startedAt: string;
endsAt?: string;
}
interface UseExperimentOptions<T = string> {
/**
* Default variant if experiment not found or user not bucketed
*/
defaultVariant?: T;
/**
* Automatically track exposure when variant is accessed
* @default true
*/
autoTrackExposure?: boolean;
/**
* Skip this experiment for certain conditions
*/
skip?: boolean;
}
Usage Examples
import { useExperiment } from '@54vie/analytics';
function PricingPage() {
const { variant, isLoading, trackConversion } = useExperiment<'control' | 'variant_a' | 'variant_b'>(
'pricing_page_layout',
{ defaultVariant: 'control' }
);
if (isLoading) {
return <LoadingSpinner />;
}
const handlePurchase = (plan: string) => {
trackConversion('purchase', { plan });
// Process purchase...
};
switch (variant) {
case 'variant_a':
return <PricingLayoutA onPurchase={handlePurchase} />;
case 'variant_b':
return <PricingLayoutB onPurchase={handlePurchase} />;
default:
return <PricingLayoutControl onPurchase={handlePurchase} />;
}
}
With TypeScript Discriminated Union
import { useExperiment } from '@54vie/analytics';
type CheckoutVariant = 'single_page' | 'multi_step' | 'express';
function Checkout() {
const { variant, trackConversion, metadata } = useExperiment<CheckoutVariant>(
'checkout_flow',
{
defaultVariant: 'multi_step',
autoTrackExposure: true,
}
);
const components: Record<CheckoutVariant, React.ComponentType<CheckoutProps>> = {
single_page: SinglePageCheckout,
multi_step: MultiStepCheckout,
express: ExpressCheckout,
};
const CheckoutComponent = components[variant];
return (
<CheckoutComponent
onComplete={() => trackConversion('checkout_complete')}
experimentMetadata={metadata}
/>
);
}
Conditional Experiments
import { useExperiment } from '@54vie/analytics';
function FeatureComponent({ user }) {
const { variant } = useExperiment('new_feature_rollout', {
defaultVariant: 'control',
// Skip experiment for admin users
skip: user.role === 'admin',
});
// Admin users always see the new feature
if (user.role === 'admin' || variant === 'enabled') {
return <NewFeature />;
}
return <LegacyFeature />;
}
usePageTracking
Hook for automatic page view tracking with route changes.
Import
import { usePageTracking } from '@54vie/analytics';
Return Type
interface UsePageTrackingReturn {
/**
* Manually track a page view
*/
trackPageView: (options?: PageViewOptions) => void;
}
interface PageViewOptions {
/**
* Override the page path
*/
path?: string;
/**
* Override the page title
*/
title?: string;
/**
* Additional properties to include
*/
properties?: EventProperties;
}
Usage Examples
// Automatic tracking with React Router
import { usePageTracking } from '@54vie/analytics';
import { useLocation } from 'react-router-dom';
function App() {
const location = useLocation();
usePageTracking({
// Tracks automatically on location change
dependencies: [location.pathname],
});
return <Routes>{/* your routes */}</Routes>;
}
// Manual tracking for specific scenarios
import { usePageTracking } from '@54vie/analytics';
function TabContainer() {
const { trackPageView } = usePageTracking();
const [activeTab, setActiveTab] = useState('overview');
const handleTabChange = (tab: string) => {
setActiveTab(tab);
trackPageView({
path: `/dashboard/${tab}`,
title: `Dashboard - ${tab}`,
properties: { tabName: tab },
});
};
return (
<Tabs value={activeTab} onChange={handleTabChange}>
{/* tabs */}
</Tabs>
);
}
useTrackOnMount
Utility hook for tracking events when a component mounts.
Import
import { useTrackOnMount } from '@54vie/analytics';
Usage
import { useTrackOnMount } from '@54vie/analytics';
function PromotionBanner({ promotion }) {
useTrackOnMount('promotion_viewed', {
promotionId: promotion.id,
promotionName: promotion.name,
placement: 'homepage_hero',
});
return <div>{/* banner content */}</div>;
}
useTrackOnUnmount
Utility hook for tracking events when a component unmounts.
Import
import { useTrackOnUnmount } from '@54vie/analytics';
Usage
import { useTrackOnUnmount } from '@54vie/analytics';
function VideoPlayer({ videoId }) {
const [watchTime, setWatchTime] = useState(0);
useTrackOnUnmount('video_session_ended', () => ({
videoId,
totalWatchTime: watchTime,
completionPercentage: calculateCompletion(watchTime),
}));
return <video onTimeUpdate={(e) => setWatchTime(e.target.currentTime)} />;
}
Hook Composition Example
import {
useAnalytics,
useUserProperties,
useExperiment,
usePageTracking,
} from '@54vie/analytics';
function Dashboard() {
const { track, userId } = useAnalytics();
const { setProperty, increment } = useUserProperties();
const { variant: dashboardVariant } = useExperiment('dashboard_redesign');
usePageTracking();
useEffect(() => {
increment('dashboardViews');
setProperty('lastDashboardVisit', new Date().toISOString());
}, []);
const handleAction = (action: string) => {
track('dashboard_action', {
action,
variant: dashboardVariant,
});
};
return (
<div className={`dashboard dashboard--${dashboardVariant}`}>
{/* dashboard content */}
</div>
);
}
Related
- Provider - AnalyticsProvider setup and configuration
- Events - StandardEvents and custom event tracking
- Experiments - A/B testing and feature flags