This commit is contained in:
Tomáš Dvořák
2025-10-16 13:32:05 +02:00
commit 12cba639b9
663 changed files with 168914 additions and 0 deletions
+482
View File
@@ -0,0 +1,482 @@
# 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
<button data-umami-event="Signup button">
Sign up
</button>
```
### With Additional Event Data
Use `data-umami-event-*` to add properties. Note: All data is saved as **strings** with this method.
```tsx
<button
data-umami-event="Newsletter Submit"
data-umami-event-location={window.location.pathname}
data-umami-event-source="homepage"
>
Subscribe
</button>
```
### Link Tracking
```tsx
<a
href="/articles/123"
data-umami-event="Article Click"
data-umami-event-id="123"
data-umami-event-title="Match Report"
>
Read Article
</a>
```
### Navigation Links
```tsx
<Link
to="/matches"
data-umami-event="Navigation"
data-umami-event-destination="matches"
>
Matches
</Link>
```
## 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
<Button
type="submit"
data-umami-event="Newsletter Submit"
data-umami-event-location={window.location.pathname}
>
Subscribe
</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
<Button
onClick={() => saveMut.mutate()}
data-umami-event="Save Preferences"
>
Save
</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
<Button
onClick={handleBackToHome}
data-umami-event="Back to Home"
data-umami-event-from="unsubscribe"
>
Back to Home
</Button>
```
### ✅ Contact Form
**File**: `frontend/src/pages/ContactPage.tsx`
```tsx
// Submit button with data attribute
<Button
type="submit"
data-umami-event="Contact Form Submit"
>
Send Message
</Button>
// 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
<IconButton
as="a"
href={facebookUrl}
onClick={() => trackSocialShare('Facebook', facebookUrl)}
aria-label="Facebook"
icon={<FiFacebook />}
/>
```
## 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
<Button
onClick={handleClick}
data-umami-event="Download" // Automatic tracking
data-umami-event-file="brochure.pdf"
>
Download
</Button>
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
<a
href={pdfUrl}
download
data-umami-event="Download"
data-umami-event-file={fileName}
data-umami-event-type="pdf"
>
Download PDF
</a>
```
### 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