Skip to main content

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>
);
}
  • Provider - AnalyticsProvider setup and configuration
  • Events - StandardEvents and custom event tracking
  • Experiments - A/B testing and feature flags