# Umami Event Tracking Implementation Guide This guide shows how to add Umami event tracking throughout your application using both **data attributes** (HTML) and **JavaScript methods**. ## Quick Reference ### When to Use Which Method - **Data Attributes (`data-umami-event`)**: Simple button clicks, links, static elements - **JavaScript (`trackEvent()`)**: Dynamic events, programmatic tracking, conditional tracking, form submissions ## Method 1: Data Attributes (Recommended for Simple Tracking) Based on [Umami documentation](https://umami.is/docs/track-events), add special data properties to any HTML element. ### Basic Button Click ```tsx ``` ### With Additional Event Data Use `data-umami-event-*` to add properties. Note: All data is saved as **strings** with this method. ```tsx ``` ### Link Tracking ```tsx Read Article ``` ### Navigation Links ```tsx Matches ``` ## Method 2: JavaScript Tracking (For Dynamic Events) Import tracking utilities and call them programmatically. This method supports all data types (numbers, booleans, objects). ### Import ```tsx import { trackEvent, trackFormSubmit, trackNewsletterSubscribe, trackContactSubmit, // ... other helpers } from '../utils/umami'; ``` ### Form Submission Tracking ```tsx const handleSubmit = async (data: FormData) => { try { await submitForm(data); // Track successful submission trackFormSubmit('Newsletter Subscribe', true); trackNewsletterSubscribe(window.location.pathname); showSuccessMessage(); } catch (error) { // Track failed submission trackFormSubmit('Newsletter Subscribe', false); showErrorMessage(); } }; ``` ### Custom Event Tracking ```tsx // Generic event with custom data trackEvent('Video Play', { videoId: '123', duration: 300, quality: 'HD' }); // Article view trackArticleView(article.id, article.title); // Search tracking trackSearch(searchQuery, resultsCount); // Social share trackSocialShare('Facebook', url); ``` ### Conditional Tracking ```tsx const handlePurchase = async (item: Product) => { const success = await processPurchase(item); if (success) { trackEvent('Purchase', { product: item.name, price: item.price, category: item.category, success: true }); } }; ``` ## Implemented Examples ### ✅ Newsletter Subscription **File**: `frontend/src/components/newsletter/NewsletterSubscribe.tsx` ```tsx // Data attribute on submit button // JavaScript tracking in handler const onSubmit = async (data: FormData) => { try { await subscribeToNewsletter(data.email); trackNewsletterSubscribe(window.location.pathname); trackFormSubmit('Newsletter Subscribe', true); } catch (error) { trackFormSubmit('Newsletter Subscribe', false); } }; ``` ### ✅ Newsletter Preferences **File**: `frontend/src/pages/NewsletterPreferencesPage.tsx` ```tsx // Save preferences button // Track in mutation success onSuccess: () => { trackEvent('Newsletter Preferences Saved', { blogs: prefs.blogs, matches: prefs.matches, events: prefs.events, scores: prefs.scores, }); } ``` ### ✅ Newsletter Unsubscribe **File**: `frontend/src/pages/NewsletterUnsubscribePage.tsx` ```tsx // Track unsubscribe completion await unsubscribeFromNewsletter(email); trackEvent('Newsletter Unsubscribe', { success: true, source: 'email_link' }); // Data attribute on button ``` ### ✅ Contact Form **File**: `frontend/src/pages/ContactPage.tsx` ```tsx // Submit button with data attribute // JavaScript tracking onSuccess: () => { trackContactSubmit(true); trackFormSubmit('Contact Form', true); }, onError: () => { trackContactSubmit(false); trackFormSubmit('Contact Form', false); } ``` ### ✅ Social Media Links **File**: `frontend/src/components/layout/Footer.tsx` ```tsx trackSocialShare('Facebook', facebookUrl)} aria-label="Facebook" icon={} /> ``` ## Available Helper Functions All functions are in `frontend/src/utils/umami.ts`: | Function | Purpose | Example | |----------|---------|---------| | `trackEvent(name, data?)` | Generic event | `trackEvent('Video Play', { id: '123' })` | | `trackButtonClick(button, location?)` | Button clicks | `trackButtonClick('Download PDF')` | | `trackFormSubmit(form, success?)` | Form submissions | `trackFormSubmit('Contact', true)` | | `trackNavigation(dest, source?)` | Page navigation | `trackNavigation('/matches')` | | `trackArticleView(id, title)` | Article views | `trackArticleView(1, 'Title')` | | `trackMatchView(id)` | Match views | `trackMatchView(123)` | | `trackSearch(query, results?)` | Search queries | `trackSearch('striker', 10)` | | `trackVideoPlay(id, title?)` | Video plays | `trackVideoPlay('abc123')` | | `trackNewsletterSubscribe(source?)` | Newsletter signup | `trackNewsletterSubscribe('/home')` | | `trackDownload(file, type?)` | File downloads | `trackDownload('brochure.pdf')` | | `trackSocialShare(platform, url?)` | Social shares | `trackSocialShare('Twitter')` | | `trackContactSubmit(success?)` | Contact form | `trackContactSubmit(true)` | ## Best Practices ### 1. Event Names - **Keep them short** (max 50 characters) - **Be descriptive but consistent** - **Use Title Case** for readability ✅ Good: - `Newsletter Submit` - `Article Click` - `Video Play` ❌ Bad: - `newsletter_submit_button_clicked_on_homepage` - `click` - `event123` ### 2. Event Data - **Use snake_case** for property names - **Keep data relevant** - don't track sensitive information - **Be consistent** across similar events ✅ Good: ```tsx trackEvent('Purchase', { product_id: '123', category: 'jersey', price: 500 }); ``` ❌ Bad: ```tsx trackEvent('Purchase', { PRODUCT_ID: '123', user_email: 'sensitive@example.com', // Don't track PII random_data: 'unnecessary' }); ``` ### 3. Combining Methods Use **both** data attributes AND JavaScript when you need tracking + custom logic: ```tsx const handleClick = () => { // Additional programmatic tracking with more context trackDownload('brochure.pdf', 'pdf'); // Your custom logic here initiateDownload(); }; ``` ### 4. Don't Over-Track Track **meaningful** user interactions, not every tiny action: ✅ Track: - Form submissions - Button clicks on CTAs - Article/video views - Downloads - Social shares - Navigation to key pages ❌ Don't track: - Mouse movements - Every scroll event - Hovering over elements - Typing in forms (privacy!) ## Testing Your Tracking ### 1. Browser Console ```javascript // Check if Umami is loaded console.log(window.umami); // Manually trigger an event window.umami?.track('Test Event', { test: true }); ``` ### 2. Network Tab 1. Open DevTools > Network 2. Filter by your Umami domain or "umami" 3. Interact with tracked elements 4. Verify requests are sent ### 3. Umami Dashboard 1. Go to `/admin/analytika` 2. Navigate to "Události" (Events) tab 3. Verify your custom events appear ## Common Patterns ### Article/Blog Post View ```tsx useEffect(() => { if (article) { trackArticleView(article.id, article.title); } }, [article]); ``` ### Search Results ```tsx const handleSearch = async (query: string) => { const results = await searchArticles(query); trackSearch(query, results.length); setResults(results); }; ``` ### Video Player ```tsx const handlePlay = (video: Video) => { trackVideoPlay(video.id, video.title); player.play(); }; ``` ### Download Links ```tsx Download PDF ``` ### Modal/Dialog Opens ```tsx const openDialog = () => { trackEvent('Modal Open', { modal: 'player_details', player_id: player.id }); setIsOpen(true); }; ``` ## Integration Checklist - [ ] Newsletter subscription form - [ ] Newsletter preferences page - [ ] Newsletter unsubscribe page - [ ] Contact form - [ ] Social media links - [ ] Article/blog post views - [ ] Match views - [ ] Video plays - [ ] File downloads - [ ] Search functionality - [ ] Navigation links - [ ] Call-to-action buttons - [ ] E-shop links (if applicable) ## Troubleshooting ### Events Not Showing Up 1. **Check if Umami script is loaded** ```javascript console.log(window.umami); // Should not be undefined ``` 2. **Verify website ID is set** - Check `/api/v1/umami/config` returns valid config 3. **Check Network tab** - Look for requests to your Umami server - Verify they return 200 OK ### Data Attributes Not Working 1. **Ensure script is loaded** before user interaction 2. **Check element syntax** - must be `data-umami-event` exactly 3. **Verify onClick handlers** aren't preventing default behavior ### JavaScript Tracking Not Working 1. **Check imports** are correct 2. **Verify function calls** happen after successful actions 3. **Check browser console** for errors ## Resources - [Umami Event Tracking Docs](https://umami.is/docs/track-events) - [Umami API Reference](https://umami.is/docs/api) - Project: `UMAMI_INTEGRATION.md` - Full integration documentation - Code: `frontend/src/utils/umami.ts` - Tracking utilities - Code: `frontend/src/hooks/useUmami.ts` - React hook