Install Umami | OpsBlu Docs

Install Umami

Install the Umami tracking tag or SDK — step-by-step embed instructions, verification, and troubleshooting.

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

  1. Script Tag (HTML) - Simplest, recommended for most websites
  2. npm Package - For JavaScript/TypeScript applications
  3. Framework-Specific - React, Vue, Next.js, Nuxt, etc.
  4. Self-Hosted - Deploy your own Umami instance

Prerequisites

Before installing Umami, you need:

For Umami Cloud:

  1. Sign up at cloud.umami.is
  2. Add your website in the dashboard
  3. Obtain your website ID and tracking script URL

For Self-Hosted Umami:

  1. Deploy Umami to your server (Vercel, Railway, Docker, etc.)
  2. Create a website in your Umami dashboard
  3. Get your website ID and self-hosted Umami URL

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):

  1. Fork Umami GitHub repository
  2. Connect to Vercel
  3. Add PostgreSQL database (Vercel Postgres)
  4. Deploy

Railway:

  1. Click "Deploy on Railway" from Umami docs
  2. Configure PostgreSQL database
  3. 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:

  1. Visit your Umami dashboard
  2. Select your website
  3. Check "Realtime" view for active visitors
  4. Navigate to "Events" tab
  5. 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

  1. Use async Attribute: Prevents blocking page load
  2. Load Early: Place script in <head> for earliest tracking
  3. Use Environment Variables: Keep website IDs in environment variables
  4. Test Before Production: Verify tracking works in development
  5. Monitor Dashboard: Regularly check analytics are being collected
  6. Version Control: Don't commit website IDs to public repositories
  7. Document Setup: Maintain documentation of website IDs and URLs
  8. 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.