Installing Umami Tracking Code
Umami offers multiple installation methods to suit different development environments and workflows. Whether you're adding Umami to a simple HTML website or integrating it into a modern JavaScript framework, there's an installation approach that fits your needs.
Installation Methods Overview
- Script Tag (HTML) - Simplest, recommended for most websites
- npm Package - For JavaScript/TypeScript applications
- Framework-Specific - React, Vue, Next.js, Nuxt, etc.
- Self-Hosted - Deploy your own Umami instance
Prerequisites
Before installing Umami, you need:
For Umami Cloud:
- Sign up at cloud.umami.is
- Add your website in the dashboard
- Obtain your website ID and tracking script URL
For Self-Hosted Umami:
- Deploy Umami to your server (Vercel, Railway, Docker, etc.)
- Create a website in your Umami dashboard
- Get your website ID and self-hosted Umami URL
Method 1: Script Tag Installation (Recommended)
The simplest installation method - add one script tag to your HTML.
Basic Installation:
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
<!-- Umami Analytics -->
<script async src="https://analytics.example.com/script.js" data-website-id="YOUR_WEBSITE_ID"></script>
</head>
<body>
<!-- Your content -->
</body>
</html>
Where to Place the Script:
<!-- Option 1: In <head> (Recommended) -->
<head>
<script async src="https://analytics.example.com/script.js" data-website-id="abc123"></script>
</head>
<!-- Option 2: Before closing </body> (Alternative) -->
<body>
<!-- Your content -->
<script async src="https://analytics.example.com/script.js" data-website-id="abc123"></script>
</body>
Cloud vs Self-Hosted URL:
<!-- Umami Cloud -->
<script async src="https://cloud.umami.is/script.js" data-website-id="abc123"></script>
<!-- Self-Hosted -->
<script async src="https://analytics.yourdomain.com/script.js" data-website-id="xyz789"></script>
Script Attributes:
<script
async
src="https://analytics.example.com/script.js"
data-website-id="YOUR_WEBSITE_ID"
data-domains="example.com,www.example.com"
data-auto-track="true">
</script>
Attribute Options:
| Attribute | Description | Example |
|---|---|---|
async |
Load script asynchronously (recommended) | async |
src |
Umami script URL | https://analytics.example.com/script.js |
data-website-id |
Your website ID (required) | abc123 |
data-domains |
Limit tracking to specific domains | example.com,www.example.com |
data-auto-track |
Auto-track page views (default: true) | true or false |
data-cache |
Enable DNS prefetching and caching | true |
Disable Auto-Tracking:
<!-- Manually control when to track page views -->
<script async
src="https://analytics.example.com/script.js"
data-website-id="abc123"
data-auto-track="false">
</script>
<script>
// Manually track page view
window.addEventListener('load', () => {
if (window.umami) {
umami.track();
}
});
</script>
Method 2: npm Package Installation
For modern JavaScript applications using npm/yarn.
Install Package:
npm install @umami/tracker
or
yarn add @umami/tracker
Initialize in Your App:
import umami from '@umami/tracker';
umami.init({
websiteId: 'YOUR_WEBSITE_ID',
hostUrl: 'https://analytics.example.com'
});
Complete Setup Example:
// analytics.js
import umami from '@umami/tracker';
const isDev = process.env.NODE_ENV === 'development';
// Initialize Umami
umami.init({
websiteId: process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID || 'default-id',
hostUrl: 'https://analytics.example.com',
domains: ['example.com', 'www.example.com'],
autoTrack: !isDev, // Don't auto-track in development
});
// Export for use throughout app
export { umami };
Track Page Views:
import { umami } from './analytics';
// Track page view
umami.track();
// Track with custom properties
umami.track(props => ({
...props,
url: '/custom-url',
referrer: '/previous-page'
}));
Track Events:
import { umami } from './analytics';
// Track custom event
umami.track('button_click', {
button_name: 'signup',
location: 'header'
});
Method 3: Framework-Specific Installation
React
Install and Setup:
npm install @umami/tracker
// src/analytics.js
import umami from '@umami/tracker';
umami.init({
websiteId: process.env.REACT_APP_UMAMI_WEBSITE_ID,
hostUrl: 'https://analytics.example.com'
});
export default umami;
Track Page Views with React Router:
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import umami from './analytics';
function App() {
const location = useLocation();
useEffect(() => {
umami.track();
}, [location.pathname, location.search]);
return (
<Router>
{/* Your routes */}
</Router>
);
}
Custom Hook for Tracking:
// useAnalytics.js
import { useCallback } from 'react';
import umami from './analytics';
export function useAnalytics() {
const trackEvent = useCallback((eventName, eventData) => {
umami.track(eventName, eventData);
}, []);
return { trackEvent };
}
// Usage in component
function MyComponent() {
const { trackEvent } = useAnalytics();
const handleClick = () => {
trackEvent('button_click', { button: 'cta' });
};
return <button Me</button>;
}
Next.js
Install Package:
npm install @umami/tracker
Create Analytics Component:
// components/Analytics.js
'use client'; // For Next.js 13+ App Router
import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
import umami from '@umami/tracker';
export function Analytics() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
umami.init({
websiteId: process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID,
hostUrl: 'https://analytics.example.com'
});
}, []);
useEffect(() => {
umami.track();
}, [pathname, searchParams]);
return null;
}
Add to Layout:
// app/layout.js (Next.js 13+ App Router)
import { Analytics } from '@/components/Analytics';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Analytics />
</body>
</html>
);
}
Alternative: Script Tag in Next.js:
// app/layout.js
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<Script
async
src="https://analytics.example.com/script.js"
data-website-id={process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID}
strategy="afterInteractive"
/>
</head>
<body>{children}</body>
</html>
);
}
Vue.js
Install and Setup:
npm install @umami/tracker
// plugins/umami.js
import umami from '@umami/tracker';
umami.init({
websiteId: import.meta.env.VITE_UMAMI_WEBSITE_ID,
hostUrl: 'https://analytics.example.com'
});
export default umami;
Track Route Changes (Vue Router):
// router/index.js
import { createRouter } from 'vue-router';
import umami from '@/plugins/umami';
const router = createRouter({
// ... router config
});
router.afterEach(() => {
umami.track();
});
export default router;
Global Mixin for Tracking:
// main.js
import { createApp } from 'vue';
import umami from './plugins/umami';
const app = createApp(App);
app.config.globalProperties.$umami = umami;
app.mount('#app');
Use in Components:
<template>
<button @click="handleClick">Track Event</button>
</template>
<script>
export default {
methods: {
handleClick() {
this.$umami.track('button_click', {
button: 'example'
});
}
}
};
</script>
Nuxt.js
Install Package:
npm install @umami/tracker
Create Plugin:
// plugins/umami.client.js
import umami from '@umami/tracker';
export default defineNuxtPlugin(() => {
umami.init({
websiteId: useRuntimeConfig().public.umamiWebsiteId,
hostUrl: 'https://analytics.example.com'
});
return {
provide: {
umami
}
};
});
Configure in nuxt.config.js:
export default defineNuxtConfig({
runtimeConfig: {
public: {
umamiWebsiteId: process.env.NUXT_PUBLIC_UMAMI_WEBSITE_ID
}
}
});
Track Page Views:
// app.vue
<script setup>
const route = useRoute();
const { $umami } = useNuxtApp();
watch(() => route.path, () => {
$umami.track();
});
</script>
Method 4: Self-Hosted Umami Installation
Quick Deploy Options:
Vercel (Recommended):
- Fork Umami GitHub repository
- Connect to Vercel
- Add PostgreSQL database (Vercel Postgres)
- Deploy
Railway:
- Click "Deploy on Railway" from Umami docs
- Configure PostgreSQL database
- Deploy
Docker:
# docker-compose.yml
version: '3'
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://username:password@db:5432/umami
DATABASE_TYPE: postgresql
APP_SECRET: replace-me-with-a-random-string
depends_on:
- db
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: username
POSTGRES_PASSWORD: password
volumes:
- umami-db-data:/var/lib/postgresql/data
volumes:
umami-db-data:
docker-compose up -d
Verification and Testing
1. Check Script Loads:
Open browser DevTools:
// In console, check if umami loaded
console.log(window.umami);
// Should show umami object if loaded successfully
2. Test Event Tracking:
// Fire test event
umami.track('test_event', { test: true });
3. Verify in Dashboard:
- Visit your Umami dashboard
- Select your website
- Check "Realtime" view for active visitors
- Navigate to "Events" tab
- Look for test events
4. Check Network Requests:
In browser DevTools Network tab:
- Filter by "send" or "collect"
- Look for requests to your Umami server
- Status should be 200 OK
Common Installation Issues
Script Not Loading:
// Check if script loaded
window.addEventListener('load', () => {
if (!window.umami) {
console.error('Umami failed to load. Check script URL and ad blockers.');
}
});
Ad Blocker Interference:
<!-- Try renaming script.js to something less obvious -->
<!-- This requires configuration in self-hosted Umami -->
<script async src="https://analytics.example.com/analytics.js" data-website-id="abc123"></script>
Wrong Website ID:
// Verify website ID in dashboard matches your code
console.log('Website ID:', 'abc123');
// Compare with Umami dashboard settings
CORS Issues (Self-Hosted):
Ensure your Umami instance allows your domain. Check Umami environment variables.
Environment-Specific Configuration
Development vs Production:
const UMAMI_CONFIG = {
websiteId: process.env.NODE_ENV === 'production'
? 'PRODUCTION_WEBSITE_ID'
: 'DEV_WEBSITE_ID',
hostUrl: 'https://analytics.example.com',
autoTrack: process.env.NODE_ENV === 'production'
};
umami.init(UMAMI_CONFIG);
Conditional Loading:
// Only load in production
if (process.env.NODE_ENV === 'production') {
umami.init({
websiteId: process.env.UMAMI_WEBSITE_ID,
hostUrl: 'https://analytics.example.com'
});
}
Best Practices
- Use
asyncAttribute: Prevents blocking page load - Load Early: Place script in
<head>for earliest tracking - Use Environment Variables: Keep website IDs in environment variables
- Test Before Production: Verify tracking works in development
- Monitor Dashboard: Regularly check analytics are being collected
- Version Control: Don't commit website IDs to public repositories
- Document Setup: Maintain documentation of website IDs and URLs
- Use Self-Hosted for Privacy: Maximum data control and privacy
Security Considerations
Protect Your Website ID:
// Use environment variables
const UMAMI_WEBSITE_ID = process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID;
// Don't hardcode in public code
// Bad
const websiteId = 'abc-123-def-456';
// Good
const websiteId = process.env.UMAMI_WEBSITE_ID;
Content Security Policy (CSP):
<meta http-equiv="Content-Security-Policy"
content="script-src 'self' https://analytics.example.com; connect-src 'self' https://analytics.example.com;">
Summary
Choose the installation method that best fits your stack:
- Simple HTML Site: Script tag
- React/Vue/Angular: npm package
- Next.js/Nuxt: Framework-specific setup
- Maximum Privacy: Self-hosted deployment
All methods provide the same tracking capabilities while respecting user privacy through Umami's cookie-free, GDPR-compliant approach.