Some checks failed
Build & Deploy KLZ Cables / deploy (push) Failing after 13m20s
1202 lines
27 KiB
Markdown
1202 lines
27 KiB
Markdown
# Umami Analytics Examples
|
|
|
|
This file contains practical examples of how to use the analytics system in various scenarios.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Basic Event Tracking](#basic-event-tracking)
|
|
2. [E-commerce Tracking](#e-commerce-tracking)
|
|
3. [Form Tracking](#form-tracking)
|
|
4. [User Authentication](#user-authentication)
|
|
5. [Search & Filtering](#search--filtering)
|
|
6. [Content Tracking](#content-tracking)
|
|
7. [Error Tracking](#error-tracking)
|
|
8. [Performance Tracking](#performance-tracking)
|
|
9. [Custom Navigation](#custom-navigation)
|
|
|
|
---
|
|
|
|
## Basic Event Tracking
|
|
|
|
### Button Click Tracking
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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.00, // Current cart total
|
|
});
|
|
|
|
// Actual add to cart logic
|
|
// addToCart(product, quantity);
|
|
};
|
|
|
|
return (
|
|
<button onClick={handleAddToCart}>
|
|
Add to Cart
|
|
</button>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Purchase Tracking
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
// __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
|
|
|
|
```tsx
|
|
// 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 NEXT_PUBLIC_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
|
|
|
|
```tsx
|
|
'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)
|
|
|
|
```tsx
|
|
'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
|
|
|
|
```tsx
|
|
'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:
|
|
1. Use the `useAnalytics` hook for client-side tracking
|
|
2. Import events from `AnalyticsEvents` for consistency
|
|
3. Include relevant context in your events
|
|
4. Respect privacy regulations (GDPR, etc.)
|
|
5. Test in development mode before deploying
|