Skip to main content

How to Self-Host Umami: Simple Web Analytics 2026

·OSSAlt Team
umamianalyticsprivacyself-hostingdockergoogle-analytics2026

TL;DR

Umami (MIT, ~21K GitHub stars, Next.js/TypeScript) is a simple, lightweight self-hosted web analytics tool. It's faster and simpler than Plausible, with a clean real-time dashboard, custom event tracking, and multi-site support. No cookies, no personal data, GDPR-compliant out of the box. The tracking script is under 2KB. Google Analytics is free but tracks users extensively; Umami gives you traffic insights without surveillance.

Key Takeaways

  • Umami: MIT, ~21K stars, Next.js — simple analytics, no cookies, real-time dashboard
  • Multi-site: Track unlimited websites from a single Umami instance
  • Teams: Share analytics access with team members per site
  • Custom events: Track clicks, form submissions, any user interaction
  • vs Plausible: Umami is simpler and lighter; Plausible has more features (funnels, revenue)
  • Share URL: Public dashboard URLs for client reporting

Part 1: Docker Setup

# docker-compose.yml
services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    container_name: umami
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: "postgresql://umami:${POSTGRES_PASSWORD}@db:5432/umami"
      DATABASE_TYPE: postgresql
      APP_SECRET: "${APP_SECRET}"
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami"]
      interval: 5s
      start_period: 20s

volumes:
  db_data:
# .env
POSTGRES_PASSWORD=your-db-password
APP_SECRET=$(openssl rand -hex 32)

docker compose up -d

Visit http://your-server:3000 → log in with admin / umamichange password immediately.


Part 2: HTTPS with Caddy

stats.yourdomain.com {
    reverse_proxy localhost:3000
}

Part 3: Add a Website

  1. Settings → Websites → + Add website
  2. Name: My Blog
  3. Domain: yourdomain.com
  4. Copy the tracking script
<!-- Add to your site's <head>: -->
<script async src="https://stats.yourdomain.com/script.js"
  data-website-id="YOUR-WEBSITE-UUID">
</script>

Part 4: Install Tracking Script

Static HTML

<head>
  <script async src="https://stats.yourdomain.com/script.js"
    data-website-id="YOUR-UUID">
  </script>
</head>

Next.js

npm install @umami/analytics
// app/layout.tsx:
import Script from 'next/script'

export default function RootLayout({ children }) {
  return (
    <html>
      <head>
        <Script
          src="https://stats.yourdomain.com/script.js"
          data-website-id="YOUR-UUID"
          strategy="afterInteractive"
        />
      </head>
      <body>{children}</body>
    </html>
  )
}

WordPress

Plugin: Insert Headers and Footers
Header section: paste script tag

Or use the official Umami WordPress plugin.

Ghost

Admin → Settings → Code injection → Site header:
<script async src="https://stats.yourdomain.com/script.js" data-website-id="UUID"></script>

Part 5: Custom Events

Track user interactions beyond page views:

// Track a button click:
document.getElementById('signup-btn').addEventListener('click', function() {
  umami.track('signup-click', { plan: 'pro' })
})

// Track form submission:
document.getElementById('contact-form').addEventListener('submit', function() {
  umami.track('form-submit', { form: 'contact' })
})

// Track with properties:
umami.track('purchase', {
  amount: 49.99,
  product: 'Pro Plan',
  currency: 'USD'
})

HTML data attributes (no JavaScript needed)

<!-- Automatically track this button click: -->
<button data-umami-event="CTA Click" data-umami-event-location="hero">
  Get Started
</button>

<!-- Track link clicks: -->
<a href="/pricing" data-umami-event="Pricing Link">View Pricing</a>

Part 6: Multi-Site Management

Add multiple sites

Settings → Websites:
├── yourdomain.com (Website 1)
├── blog.yourdomain.com (Website 2)
├── client-a.com (Website 3)
└── client-b.com (Website 4)

Each site gets its own unique tracking script with a different data-website-id.

Teams

  1. Settings → Teams → + Create team
  2. Add members: client@example.com → Viewer access
  3. Share only the sites you want them to see
  1. Website → Edit → Enable share URL
  2. Share the read-only link with clients: https://stats.yourdomain.com/share/TOKEN/site-name

Part 7: Dashboard Overview

The Umami dashboard shows:

Overview:
├── Visitors (unique)
├── Views (total page views)
├── Sessions
├── Bounce rate
└── Average session duration

Sources:
├── Referrers
├── Browsers
├── Operating systems
└── Devices (desktop/mobile/tablet)

Pages:
├── Most visited pages
└── Entry/exit pages

Location:
├── Countries
├── Regions
└── Cities (if enabled)

Events:
└── Custom event counts and properties

Part 8: API

API_KEY="your-api-key"  # Settings → API Keys
BASE="https://stats.yourdomain.com/api"
WEBSITE_ID="your-website-uuid"

# Get website stats:
curl "$BASE/websites/$WEBSITE_ID/stats?startAt=1704067200000&endAt=$(date +%s)000" \
  -H "x-umami-api-key: $API_KEY" | jq '.pageviews'

# Get top pages:
curl "$BASE/websites/$WEBSITE_ID/metrics?startAt=1704067200000&endAt=$(date +%s)000&type=url" \
  -H "x-umami-api-key: $API_KEY" | jq '.[0:10]'

# Get active visitors right now:
curl "$BASE/websites/$WEBSITE_ID/active" \
  -H "x-umami-api-key: $API_KEY"

# Send a custom event via API (server-side tracking):
curl -X POST "$BASE/send" \
  -H "Content-Type: application/json" \
  -d '{
    "payload": {
      "website": "YOUR-WEBSITE-UUID",
      "url": "/api/checkout",
      "name": "Purchase",
      "data": {"amount": 49.99, "plan": "pro"}
    },
    "type": "event"
  }'

Maintenance

# Update:
docker compose pull
docker compose up -d

# Backup:
docker exec umami-db-1 pg_dump -U umami umami \
  | gzip > umami-db-$(date +%Y%m%d).sql.gz

# Logs:
docker compose logs -f umami

See also: Plausible Analytics — more features; Matomo — enterprise-grade

See all open source analytics tools at OSSAlt.com/categories/analytics.

Comments