Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 1m14s
Build & Deploy / 🧪 QA (push) Successful in 3m20s
Build & Deploy / 🧪 Smoke Test (push) Failing after 49s
Build & Deploy / ⚡ Lighthouse (push) Successful in 3m24s
Build & Deploy / 🏗️ Build (push) Successful in 3m2s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🔔 Notify (push) Successful in 2s
26 KiB
26 KiB
Umami Analytics Examples
This file contains practical examples of how to use the analytics system in various scenarios.
Table of Contents
- Basic Event Tracking
- E-commerce Tracking
- Form Tracking
- User Authentication
- Search & Filtering
- Content Tracking
- Error Tracking
- Performance Tracking
- Custom Navigation
Basic Event Tracking
Button Click Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function CallToAction() {
const { trackEvent } = useAnalytics();
const handleClick = () => {
trackEvent(AnalyticsEvents.BUTTON_CLICK, {
button_id: 'cta-primary',
button_text: 'Get Started',
page: 'homepage',
section: 'hero',
});
};
return (
<button onClick={handleClick} className="cta-button">
Get Started
</button>
);
}
Link Click Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function NavigationLink({ href, children }) {
const { trackEvent } = useAnalytics();
const handleClick = () => {
trackEvent(AnalyticsEvents.LINK_CLICK, {
link_url: href,
link_text: children,
link_type: 'navigation',
});
};
return (
<a href={href} onClick={handleClick}>
{children}
</a>
);
}
E-commerce Tracking
Product Page View
'use client';
import { useEffect } from 'react';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
interface Product {
id: string;
name: string;
category: string;
price: number;
sku: string;
}
function ProductPage({ product }: { product: Product }) {
const { trackEvent } = useAnalytics();
useEffect(() => {
// Track product view when page loads
trackEvent(AnalyticsEvents.PRODUCT_VIEW, {
product_id: product.id,
product_name: product.name,
product_category: product.category,
product_sku: product.sku,
price: product.price,
currency: 'EUR',
});
}, [product]);
return (
<div>
<h1>{product.name}</h1>
<p>€{product.price}</p>
</div>
);
}
Add to Cart
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function AddToCartButton({ product, quantity = 1 }) {
const { trackEvent } = useAnalytics();
const handleAddToCart = () => {
trackEvent(AnalyticsEvents.PRODUCT_ADD_TO_CART, {
product_id: product.id,
product_name: product.name,
product_category: product.category,
price: product.price,
quantity: quantity,
cart_total: 150.0, // Current cart total
});
// Actual add to cart logic
// addToCart(product, quantity);
};
return <button onClick={handleAddToCart}>Add to Cart</button>;
}
Purchase Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function CheckoutComplete({ order }) {
const { trackEvent } = useAnalytics();
useEffect(() => {
// Track purchase when checkout completes
trackEvent(AnalyticsEvents.PRODUCT_PURCHASE, {
transaction_id: order.id,
transaction_total: order.total,
transaction_currency: 'EUR',
transaction_tax: order.tax,
transaction_shipping: order.shipping,
product_count: order.items.length,
products: order.items.map((item) => ({
product_id: item.product.id,
product_name: item.product.name,
quantity: item.quantity,
price: item.price,
})),
});
}, [order]);
return <div>Order Complete!</div>;
}
Wishlist Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function WishlistButton({ product }) {
const { trackEvent } = useAnalytics();
const [isInWishlist, setIsInWishlist] = useState(false);
const toggleWishlist = () => {
const newState = !isInWishlist;
trackEvent(
newState ? AnalyticsEvents.PRODUCT_WISHLIST_ADD : AnalyticsEvents.PRODUCT_WISHLIST_REMOVE,
{
product_id: product.id,
product_name: product.name,
product_category: product.category,
},
);
setIsInWishlist(newState);
// Update wishlist in backend
};
return <button onClick={toggleWishlist}>{isInWishlist ? '❤️' : '🤍'}</button>;
}
Form Tracking
Contact Form
'use client';
import { useState } from 'react';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function ContactForm() {
const { trackEvent } = useAnalytics();
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Track form start
trackEvent(AnalyticsEvents.FORM_START, {
form_id: 'contact-form',
form_name: 'Contact Us',
});
// Track form submission
trackEvent(AnalyticsEvents.FORM_SUBMIT, {
form_id: 'contact-form',
form_name: 'Contact Us',
form_fields: {
name: formData.name,
email: formData.email,
message_length: formData.message.length,
},
});
// Submit form
// submitContactForm(formData);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
setFormData((prev) => ({
...prev,
[e.target.name]: e.target.value,
}));
};
return (
<form onSubmit={handleSubmit}>
<input name="name" onChange={handleChange} />
<input name="email" onChange={handleChange} />
<textarea name="message" onChange={handleChange} />
<button type="submit">Send</button>
</form>
);
}
Newsletter Signup
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function NewsletterSignup() {
const { trackEvent } = useAnalytics();
const handleSubscribe = (email: string) => {
trackEvent(AnalyticsEvents.NEWSLETTER_SUBSCRIBE, {
email: email,
source: 'footer',
newsletter_type: 'weekly',
});
// Subscribe to newsletter
// subscribeToNewsletter(email);
};
return (
<div>
<input placeholder="Enter email" />
<button onClick={() => handleSubscribe('user@example.com')}>Subscribe</button>
</div>
);
}
Quote Request Form
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function QuoteRequestForm() {
const { trackEvent } = useAnalytics();
const handleSubmit = (formData: FormData) => {
trackEvent(AnalyticsEvents.QUOTE_REQUEST, {
form_id: 'quote-request',
product_type: formData.get('product_type'),
quantity: formData.get('quantity'),
company_size: formData.get('company_size'),
urgency: formData.get('urgency'),
});
// Submit quote request
// submitQuoteRequest(formData);
};
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button type="submit">Request Quote</button>
</form>
);
}
User Authentication
Login Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function LoginForm() {
const { trackEvent } = useAnalytics();
const handleLogin = async (email: string, password: string) => {
try {
// Track login attempt
trackEvent(AnalyticsEvents.USER_LOGIN, {
user_email: email,
login_method: 'email',
login_status: 'attempt',
});
// Perform login
// await login(email, password);
// Track successful login
trackEvent(AnalyticsEvents.USER_LOGIN, {
user_email: email,
login_method: 'email',
login_status: 'success',
});
} catch (error) {
// Track failed login
trackEvent(AnalyticsEvents.USER_LOGIN, {
user_email: email,
login_method: 'email',
login_status: 'failed',
error_message: error.message,
});
}
};
return (
<form
onSubmit={(e) => {
e.preventDefault();
handleLogin('user@example.com', 'password');
}}
>
{/* Form fields */}
<button type="submit">Login</button>
</form>
);
}
Signup Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function SignupForm() {
const { trackEvent } = useAnalytics();
const handleSignup = (userData: { email: string; name: string; company?: string }) => {
trackEvent(AnalyticsEvents.USER_SIGNUP, {
user_email: userData.email,
user_name: userData.name,
company: userData.company,
signup_method: 'email',
signup_source: 'homepage',
});
// Perform signup
// signup(userData);
};
return (
<form
onSubmit={(e) => {
e.preventDefault();
handleSignup({
email: 'user@example.com',
name: 'John Doe',
company: 'ACME Corp',
});
}}
>
{/* Form fields */}
<button type="submit">Sign Up</button>
</form>
);
}
Search & Filtering
Search Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function SearchBar() {
const { trackEvent } = useAnalytics();
const [query, setQuery] = useState('');
const handleSearch = () => {
trackEvent(AnalyticsEvents.SEARCH, {
search_query: query,
search_results_count: 42, // You'd get this from your search results
search_filters: {
category: 'cables',
voltage: 'high',
},
});
// Perform search
// performSearch(query);
};
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search products..."
/>
<button onClick={handleSearch}>Search</button>
</div>
);
}
Filter Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function ProductFilters() {
const { trackEvent } = useAnalytics();
const [filters, setFilters] = useState({
category: '',
voltage: '',
material: '',
});
const handleFilterChange = (filterType: string, value: string) => {
const newFilters = {
...filters,
[filterType]: value,
};
trackEvent(AnalyticsEvents.FILTER_APPLY, {
filter_type: filterType,
filter_value: value,
filter_count: Object.values(newFilters).filter(Boolean).length,
all_filters: newFilters,
});
setFilters(newFilters);
// Apply filters
// applyFilters(newFilters);
};
const handleClearFilters = () => {
trackEvent(AnalyticsEvents.FILTER_CLEAR, {
previous_filters: filters,
});
setFilters({
category: '',
voltage: '',
material: '',
});
// Clear filters
// clearFilters();
};
return (
<div>
<select onChange={(e) => handleFilterChange('category', e.target.value)}>
<option value="">All Categories</option>
<option value="cables">Cables</option>
<option value="connectors">Connectors</option>
</select>
<button onClick={handleClearFilters}>Clear Filters</button>
</div>
);
}
Content Tracking
Blog Post View
'use client';
import { useEffect } from 'react';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
interface BlogPost {
id: string;
title: string;
category: string;
author: string;
}
function BlogPostPage({ post }: { post: BlogPost }) {
const { trackEvent } = useAnalytics();
useEffect(() => {
trackEvent(AnalyticsEvents.BLOG_POST_VIEW, {
post_id: post.id,
post_title: post.title,
post_category: post.category,
post_author: post.author,
});
}, [post]);
return (
<article>
<h1>{post.title}</h1>
<p>By {post.author}</p>
{/* Post content */}
</article>
);
}
Video Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function VideoPlayer({ videoId, videoTitle }) {
const { trackEvent } = useAnalytics();
const handlePlay = () => {
trackEvent(AnalyticsEvents.VIDEO_PLAY, {
video_id: videoId,
video_title: videoTitle,
});
};
const handlePause = () => {
trackEvent(AnalyticsEvents.VIDEO_PAUSE, {
video_id: videoId,
video_title: videoTitle,
});
};
const handleComplete = () => {
trackEvent(AnalyticsEvents.VIDEO_COMPLETE, {
video_id: videoId,
video_title: videoTitle,
});
};
return (
<video onPlay={handlePlay} onPause={handlePause} onEnded={handleComplete}>
<source src="/video.mp4" type="video/mp4" />
</video>
);
}
Download Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function DownloadButton({ fileName, fileType, fileSize }) {
const { trackEvent } = useAnalytics();
const handleDownload = () => {
trackEvent(AnalyticsEvents.DOWNLOAD, {
file_name: fileName,
file_type: fileType,
file_size: fileSize,
download_source: 'product-page',
});
// Trigger download
// window.location.href = `/downloads/${fileName}`;
};
return <button onClick={handleDownload}>Download {fileName}</button>;
}
Error Tracking
Error Boundary
'use client';
import { Component, ErrorInfo, ReactNode } from 'react';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode;
}
class ErrorBoundary extends Component<ErrorBoundaryProps> {
state = { hasError: false, error: null };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
const { trackEvent } = useAnalytics();
trackEvent(AnalyticsEvents.ERROR, {
error_message: error.message,
error_stack: error.stack,
error_component: errorInfo.componentStack,
error_type: error.name,
});
}
render() {
if (this.state.hasError) {
return this.props.fallback ?? <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// Usage
function App() {
return (
<ErrorBoundary>
<MainContent />
</ErrorBoundary>
);
}
API Error Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function ApiClient() {
const { trackEvent } = useAnalytics();
const fetchData = async (endpoint: string) => {
try {
const response = await fetch(endpoint);
if (!response.ok) {
trackEvent(AnalyticsEvents.API_ERROR, {
endpoint: endpoint,
status_code: response.status,
error_message: response.statusText,
});
throw new Error(`HTTP ${response.status}`);
}
trackEvent(AnalyticsEvents.API_SUCCESS, {
endpoint: endpoint,
status_code: response.status,
});
return await response.json();
} catch (error) {
trackEvent(AnalyticsEvents.API_ERROR, {
endpoint: endpoint,
error_message: error.message,
error_type: error.name,
});
throw error;
}
};
return { fetchData };
}
Performance Tracking
Page Load Performance
'use client';
import { useEffect } from 'react';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function PerformanceTracker() {
const { trackEvent } = useAnalytics();
useEffect(() => {
// Track page load performance
if ('performance' in window) {
const perfData = window.performance.timing;
const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;
trackEvent(AnalyticsEvents.PERFORMANCE, {
metric: 'page_load_time',
value: pageLoadTime,
page: window.location.pathname,
});
}
}, []);
return null;
}
Custom Performance Metrics
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function ComponentWithPerformance() {
const { trackEvent } = useAnalytics();
const [loadTime, setLoadTime] = useState(0);
useEffect(() => {
const startTime = performance.now();
// Simulate some async work
setTimeout(() => {
const endTime = performance.now();
const duration = endTime - startTime;
setLoadTime(duration);
trackEvent(AnalyticsEvents.PERFORMANCE, {
metric: 'component_load_time',
value: duration,
component_name: 'ComponentWithPerformance',
});
}, 1000);
}, []);
return <div>Loaded in {loadTime}ms</div>;
}
Custom Navigation
SPA Navigation Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
function SpaNavigation() {
const { trackPageview } = useAnalytics();
const navigateTo = (path: string) => {
// Track the navigation
trackPageview(path);
// Perform navigation
window.history.pushState({}, '', path);
// Or use your router: router.push(path);
};
return (
<nav>
<button onClick={() => navigateTo('/products')}>Products</button>
<button onClick={() => navigateTo('/about')}>About</button>
<button onClick={() => navigateTo('/contact')}>Contact</button>
</nav>
);
}
Modal Navigation
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function ModalWithTracking({ modalId, children }) {
const { trackEvent, trackPageview } = useAnalytics();
const openModal = () => {
trackEvent(AnalyticsEvents.MODAL_OPEN, {
modal_id: modalId,
});
// Track modal as a "page" view
trackPageview(`/modal/${modalId}`);
};
const closeModal = () => {
trackEvent(AnalyticsEvents.MODAL_CLOSE, {
modal_id: modalId,
});
// Track return to previous page
trackPageview(window.location.pathname);
};
return (
<div>
<button onClick={openModal}>Open Modal</button>
<div className="modal">
{children}
<button onClick={closeModal}>Close</button>
</div>
</div>
);
}
Business-Specific Events
KLZ Cables Specific Examples
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
function CableProductPage({ cable }) {
const { trackEvent } = useAnalytics();
const handleTechnicalSpecDownload = () => {
trackEvent('technical_spec_download', {
cable_id: cable.id,
cable_type: cable.type,
cable_voltage: cable.voltage,
cable_standard: cable.standard,
document_type: 'datasheet',
});
};
const handleRequestQuote = () => {
trackEvent('quote_request', {
cable_id: cable.id,
cable_type: cable.type,
cable_voltage: cable.voltage,
cable_length: cable.length,
cable_quantity: cable.quantity,
project_type: cable.projectType,
urgency: cable.urgency,
});
};
const handleBrochureDownload = () => {
trackEvent('brochure_download', {
brochure_type: 'product',
cable_category: cable.category,
language: 'de',
});
};
return (
<div>
<h1>{cable.name}</h1>
<button onClick={handleTechnicalSpecDownload}>Download Technical Specs</button>
<button onClick={handleRequestQuote}>Request Quote</button>
<button onClick={handleBrochureDownload}>Download Brochure</button>
</div>
);
}
Wind Farm Construction Tracking
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
function WindFarmProjectPage({ project }) {
const { trackEvent } = useAnalytics();
const handleProjectInquiry = () => {
trackEvent('project_inquiry', {
project_type: 'wind_farm',
project_location: project.location,
project_size: project.size,
project_stage: project.stage,
cable_requirements: project.cableRequirements,
});
};
const handleCableCalculation = () => {
trackEvent('cable_calculation', {
calculation_type: 'voltage_drop',
cable_type: project.cableType,
cable_length: project.cableLength,
load_current: project.loadCurrent,
result: project.calculationResult,
});
};
return (
<div>
<h1>{project.name}</h1>
<button onClick={handleProjectInquiry}>Request Project Consultation</button>
<button onClick={handleCableCalculation}>Calculate Cable Requirements</button>
</div>
);
}
Testing Analytics
Mock Analytics for Tests
// __tests__/analytics-mock.ts
export const mockAnalytics = {
track: jest.fn(),
trackPageview: jest.fn(),
};
jest.mock('@/lib/services/create-services', () => ({
getAppServices: () => ({
analytics: mockAnalytics,
}),
}));
// Usage in tests
import { render, screen, fireEvent } from '@testing-library/react';
import { mockAnalytics } from './analytics-mock';
import { useAnalytics } from '@/components/analytics/useAnalytics';
test('tracks button click', () => {
const TestComponent = () => {
const { trackEvent } = useAnalytics();
return <button onClick={() => trackEvent('test_event')}>Click</button>;
};
render(<TestComponent />);
fireEvent.click(screen.getByText('Click'));
expect(mockAnalytics.track).toHaveBeenCalledWith('test_event');
});
Development Mode Testing
// In development mode, check console logs:
// [Umami] Tracked event: product_add_to_cart { product_id: '123' }
// [Umami] Tracked pageview: /products/123
// To test without sending data to Umami:
// 1. Remove UMAMI_WEBSITE_ID from .env
// 2. Or set it to an empty string
// 3. Check console logs to verify events are being tracked
Performance Tips
1. Debounce High-Frequency Events
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { debounce } from 'lodash';
function SearchInput() {
const { trackEvent } = useAnalytics();
const debouncedTrack = debounce((query: string) => {
trackEvent('search', { search_query: query });
}, 500);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
debouncedTrack(e.target.value);
};
return <input onChange={handleChange} />;
}
2. Batch Events (if needed)
'use client';
import { useAnalytics } from '@/components/analytics/useAnalytics';
function BatchTracker() {
const { trackEvent } = useAnalytics();
const eventQueue = useRef<Array<{ name: string; props: any }>>([]);
const addToQueue = (name: string, props: any) => {
eventQueue.current.push({ name, props });
};
const flushQueue = () => {
eventQueue.current.forEach(({ name, props }) => {
trackEvent(name, props);
});
eventQueue.current = [];
};
// Flush queue on page unload
useEffect(() => {
const handleBeforeUnload = () => flushQueue();
window.addEventListener('beforeunload', handleBeforeUnload);
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
}, []);
return null;
}
3. Use Web Vitals for Performance
'use client';
import { useEffect } from 'react';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
function WebVitalsTracker() {
const { trackEvent } = useAnalytics();
useEffect(() => {
// Track Core Web Vitals
if ('PerformanceObserver' in window) {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'largest-contentful-paint') {
trackEvent(AnalyticsEvents.PERFORMANCE, {
metric: 'lcp',
value: entry.startTime,
});
}
if (entry.entryType === 'first-input-delay') {
trackEvent(AnalyticsEvents.PERFORMANCE, {
metric: 'fid',
value: entry.processingStart - entry.startTime,
});
}
if (entry.entryType === 'layout-shift') {
trackEvent(AnalyticsEvents.PERFORMANCE, {
metric: 'cls',
value: entry.value,
});
}
}
});
observer.observe({
entryTypes: ['largest-contentful-paint', 'first-input-delay', 'layout-shift'],
});
}
}, []);
return null;
}
Summary
This examples file demonstrates how to implement comprehensive analytics tracking for various scenarios:
- ✅ Basic interactions (buttons, links, forms)
- ✅ E-commerce (product views, cart, purchases)
- ✅ User authentication (login, signup, logout)
- ✅ Search & filtering (search queries, filter applications)
- ✅ Content tracking (blog posts, videos, downloads)
- ✅ Error tracking (error boundaries, API errors)
- ✅ Performance tracking (page loads, custom metrics)
- ✅ Custom navigation (SPA, modals)
- ✅ Business-specific events (KLZ Cables, wind farms)
Remember to:
- Use the
useAnalyticshook for client-side tracking - Import events from
AnalyticsEventsfor consistency - Include relevant context in your events
- Respect privacy regulations (GDPR, etc.)
- Test in development mode before deploying