10 KiB
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, add special data properties to any HTML element.
Basic Button Click
<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.
<button
data-umami-event="Newsletter Submit"
data-umami-event-location={window.location.pathname}
data-umami-event-source="homepage"
>
Subscribe
</button>
Link Tracking
<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
<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
import {
trackEvent,
trackFormSubmit,
trackNewsletterSubscribe,
trackContactSubmit,
// ... other helpers
} from '../utils/umami';
Form Submission Tracking
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
// 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
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
// 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
// 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
// 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
// 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
<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 SubmitArticle ClickVideo Play
❌ Bad:
newsletter_submit_button_clicked_on_homepageclickevent123
2. Event Data
- Use snake_case for property names
- Keep data relevant - don't track sensitive information
- Be consistent across similar events
✅ Good:
trackEvent('Purchase', {
product_id: '123',
category: 'jersey',
price: 500
});
❌ Bad:
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:
<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
// Check if Umami is loaded
console.log(window.umami);
// Manually trigger an event
window.umami?.track('Test Event', { test: true });
2. Network Tab
- Open DevTools > Network
- Filter by your Umami domain or "umami"
- Interact with tracked elements
- Verify requests are sent
3. Umami Dashboard
- Go to
/admin/analytika - Navigate to "Události" (Events) tab
- Verify your custom events appear
Common Patterns
Article/Blog Post View
useEffect(() => {
if (article) {
trackArticleView(article.id, article.title);
}
}, [article]);
Search Results
const handleSearch = async (query: string) => {
const results = await searchArticles(query);
trackSearch(query, results.length);
setResults(results);
};
Video Player
const handlePlay = (video: Video) => {
trackVideoPlay(video.id, video.title);
player.play();
};
Download Links
<a
href={pdfUrl}
download
data-umami-event="Download"
data-umami-event-file={fileName}
data-umami-event-type="pdf"
>
Download PDF
</a>
Modal/Dialog Opens
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
-
Check if Umami script is loaded
console.log(window.umami); // Should not be undefined -
Verify website ID is set
- Check
/api/v1/umami/configreturns valid config
- Check
-
Check Network tab
- Look for requests to your Umami server
- Verify they return 200 OK
Data Attributes Not Working
- Ensure script is loaded before user interaction
- Check element syntax - must be
data-umami-eventexactly - Verify onClick handlers aren't preventing default behavior
JavaScript Tracking Not Working
- Check imports are correct
- Verify function calls happen after successful actions
- Check browser console for errors
Resources
- Umami Event Tracking Docs
- Umami API Reference
- Project:
UMAMI_INTEGRATION.md- Full integration documentation - Code:
frontend/src/utils/umami.ts- Tracking utilities - Code:
frontend/src/hooks/useUmami.ts- React hook