← All articles
ANALYTICS Umami: Simple, Private Web Analytics You Can Self-Host 2026-02-09 · umami · analytics · privacy

Umami: Simple, Private Web Analytics You Can Self-Host

Analytics 2026-02-09 umami analytics privacy google-analytics docker

Google Analytics is everywhere. It's on over half of all websites, and for good reason — it's powerful, it's free, and it's what everyone knows. But that ubiquity comes at a cost that's increasingly hard to ignore.

Your visitors' data flows to Google's servers, where it feeds ad targeting across the web. Your site needs a cookie consent banner in the EU (and increasingly elsewhere). GA4's interface requires a certification course to navigate. And if you're running a small or medium website, 95% of Google Analytics' features are noise you'll never touch.

Umami is a different kind of analytics tool. It's open source, self-hosted, privacy-focused, and radically simple. No cookies, no consent banners, no personal data collection — just clean metrics about how people use your site, presented on a single dashboard you can understand at a glance.

What Is Umami?

Umami is a self-hosted web analytics application built with Next.js and Prisma. It was created by Mike Cao in 2020 as a response to the growing complexity of Google Analytics and increasing privacy regulations.

The core philosophy is minimalism: track what matters, respect visitor privacy, and keep the interface clean enough that you actually use it.

Here's what makes Umami different:

Umami also offers a hosted cloud version if you don't want to manage your own server, but self-hosting is where the tool really shines — zero cost for unlimited sites and unlimited traffic.

Umami vs Plausible vs Google Analytics

If you're exploring privacy-friendly analytics, you've probably also come across Plausible. Both are excellent tools, but they make different trade-offs.

Feature Google Analytics Plausible Umami
Script size ~45 KB < 1 KB < 2 KB
Cookie usage Yes No No
GDPR compliance Requires consent By default By default
Data ownership Google's servers Your server (or theirs) Your server (or theirs)
Custom events Yes (complex) Yes Yes
Funnels Yes Yes (paid/self-hosted) No
Revenue tracking Yes Yes No
API access Yes Yes Yes
Dashboard Complex, multi-page Single page Single page
Database N/A ClickHouse + PostgreSQL PostgreSQL or MySQL
Self-hosting complexity N/A Moderate (3 containers) Simple (2 containers)
Self-hosting RAM N/A 2-4 GB minimum 512 MB - 1 GB minimum
Cloud pricing Free From $9/month From $9/month
License Proprietary AGPL MIT

The key differences between Umami and Plausible:

Umami is lighter. It uses PostgreSQL or MySQL as its only data store — no ClickHouse needed. This means you can run it on a 1 GB VPS, which is significant for budget self-hosters. Plausible's ClickHouse dependency means it needs at least 2 GB RAM to be stable.

Plausible has more features. Plausible offers funnels, revenue tracking, and some reporting features that Umami doesn't. If you need those, Plausible is the better fit.

Umami has a more permissive license. Umami uses MIT. Plausible uses AGPL, which has implications if you want to modify and distribute the code.

Both are excellent choices. If you already run PostgreSQL and want the simplest possible setup, Umami is hard to beat. If you need more advanced analytics features and don't mind the extra resource overhead, Plausible is a great option too.

Installation with Docker Compose

Umami's Docker setup is straightforward. You need two containers: the Umami application and a PostgreSQL database.

Prerequisites

Docker Compose file

Create a directory for your Umami installation and add this docker-compose.yml:

services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://umami:your-secure-password@db:5432/umami
      DATABASE_TYPE: postgresql
      APP_SECRET: your-random-secret-string
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: your-secure-password
    volumes:
      - umami-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami"]
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  umami-db:

Generate a proper secret for APP_SECRET:

openssl rand -base64 32

Replace your-secure-password with a strong database password and your-random-secret-string with the generated secret.

Start the services

docker compose up -d

That's it — two containers. Umami is now running on port 3000.

MySQL alternative

If you prefer MySQL, swap the image tags and database configuration:

services:
  umami:
    image: ghcr.io/umami-software/umami:mysql-latest
    environment:
      DATABASE_URL: mysql://umami:your-secure-password@db:3306/umami
      DATABASE_TYPE: mysql
      APP_SECRET: your-random-secret-string
    # ... rest stays the same

  db:
    image: mysql:8
    environment:
      MYSQL_DATABASE: umami
      MYSQL_USER: umami
      MYSQL_PASSWORD: your-secure-password
      MYSQL_ROOT_PASSWORD: your-root-password
    volumes:
      - umami-db:/var/lib/mysql

PostgreSQL is the recommended choice. It's what the Umami team primarily tests against, and it tends to perform better for analytics workloads.

Initial Setup

Creating your account

Visit http://your-server:3000 (or your domain, once you've set up a reverse proxy). You'll see the login page.

The default credentials are:

Log in and immediately change the password under Settings > Profile.

Adding your first website

  1. Go to Settings > Websites
  2. Click Add website
  3. Enter a name (for your reference) and the domain
  4. Click Save

Umami generates a unique tracking code for each site. Click the site you just added to see your tracking script.

Adding the Tracking Script

Basic HTML

Add the tracking script to the <head> of your website. Umami gives you the exact snippet:

<script defer src="https://analytics.yourdomain.com/script.js"
  data-website-id="your-website-id"></script>

The data-website-id is a UUID that Umami generates for each site. It's safe to expose in your HTML — it only identifies which site the data belongs to.

Next.js

In Next.js with the App Router, add it to your root layout:

// app/layout.tsx
import Script from "next/script";

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

Astro

In Astro, add it to your base layout component:

---
// src/layouts/BaseLayout.astro
---
<html>
  <head>
    <script defer
      src="https://analytics.yourdomain.com/script.js"
      data-website-id="your-website-id"></script>
  </head>
  <body>
    <slot />
  </body>
</html>

Hugo

In Hugo, add the script to your layouts/partials/head.html:

<script defer src="https://analytics.yourdomain.com/script.js"
  data-website-id="your-website-id"></script>

WordPress

You can use a plugin like "Insert Headers and Footers" or add it directly to your theme's header.php. Alternatively, the community maintains a dedicated Umami WordPress plugin.

Dashboard Walkthrough

Once your tracking script is collecting data, your Umami dashboard shows:

Core metrics (at a glance)

Detailed breakdowns

Realtime view

Umami shows a live count of current visitors and a realtime event stream. It's not as elaborate as Google Analytics' Realtime report, but it's useful for seeing immediate traffic after sharing a link or publishing content.

Time ranges

You can view data for today, yesterday, the last 7 days, last 30 days, last 90 days, this month, last month, or any custom date range. Umami stores data indefinitely by default, so your historical data grows over time.

Custom Events

Page views are tracked automatically, but you often want to know about specific interactions — button clicks, form submissions, file downloads, feature usage.

Tracking events in JavaScript

Umami provides a global umami object for custom event tracking:

// Track a simple event
umami.track("signup-button-click");

// Track an event with custom properties
umami.track("purchase", {
  product: "Pro Plan",
  price: 29.99,
  currency: "USD"
});

// Track a form submission
document.querySelector("#contact-form").addEventListener("submit", () => {
  umami.track("contact-form-submit");
});

Using data attributes

For simpler cases, you can track events declaratively with HTML attributes — no JavaScript required:

<button data-umami-event="signup-click">Sign Up</button>

<a href="/pricing" data-umami-event="pricing-link"
   data-umami-event-source="homepage">View Pricing</a>

<button data-umami-event="download"
        data-umami-event-file="whitepaper.pdf">Download PDF</button>

Any element with data-umami-event automatically sends an event when clicked. Additional data-umami-event-* attributes are sent as custom properties.

Viewing event data

Events appear in the Events section of your dashboard. You can see event counts over time and filter by event name. Custom properties are visible when you click into an individual event type.

Teams and Sharing

Multiple users

Umami supports multiple user accounts with different permission levels:

Create additional users under Settings > Users. This is useful if you manage analytics for multiple clients or have a team that needs dashboard access.

Team workspaces

Umami supports teams — groups of users that share access to a set of websites. Each team has its own set of websites and members, making it easy to organize access by project, client, or department.

Public dashboards

You can share any website's dashboard publicly by enabling the share URL in the site settings. This generates a unique link anyone can access without logging in — useful for transparently sharing your site's traffic numbers.

Some open source projects and indie makers use public Umami dashboards to share their traffic stats as a signal of credibility.

Performance and Resource Usage

This is where Umami really differentiates itself. It's remarkably lightweight.

Server resources

In practice, a typical Umami installation tracking a few sites with moderate traffic (under 100K pageviews/month) uses:

Resource Usage
RAM (Umami app) 100-200 MB
RAM (PostgreSQL) 100-300 MB
CPU Negligible (< 5% on a single core)
Disk (database) ~1 GB per million pageviews
Network Minimal

Compare this to Plausible, which needs ClickHouse and recommends 2-4 GB of RAM minimum. Umami can comfortably run on a $4-6/month VPS alongside other services.

Client-side impact

The tracking script is under 2 KB gzipped. It loads asynchronously with the defer attribute, so it never blocks page rendering. There's no visual impact on your site — no cookie banner, no loading indicator, nothing.

For comparison:

Tool Script size (gzipped)
Google Analytics (GA4) ~45 KB
Matomo ~22 KB
Plausible < 1 KB
Umami < 2 KB
Fathom ~6 KB

Plausible edges out Umami on raw script size, but both are so small that the difference is imperceptible. Either is a massive improvement over GA4.

Comparison: Umami vs Plausible vs Matomo vs Fathom vs GoAccess

If you're evaluating self-hosted analytics, here's how the main options stack up:

Feature Umami Plausible Matomo Fathom GoAccess
Type Web app Web app Web app Web app Log analyzer
License MIT AGPL GPL Proprietary MIT
Cookies No No Optional No N/A (server-side)
GDPR by default Yes Yes Configurable Yes Yes
Script size < 2 KB < 1 KB ~22 KB ~6 KB None (server logs)
Custom events Yes Yes Yes Yes No
Funnels No Yes Yes No No
Heatmaps No No Yes (plugin) No No
Session recording No No Yes (plugin) No No
E-commerce tracking No Revenue goals Yes No No
Self-host complexity Low Moderate High N/A (SaaS only) Very low
Min RAM (self-hosted) 512 MB 2 GB 2 GB N/A 64 MB
Database PostgreSQL/MySQL PostgreSQL + ClickHouse MySQL/MariaDB N/A None (flat files)
API Yes Yes Yes Yes No
Cloud option Yes ($9+/mo) Yes ($9+/mo) Yes ($19+/mo) Yes ($14+/mo) No
Multi-site Yes Yes Yes Yes (paid) Manual
Realtime Yes Yes Yes Yes Yes
Best for Simplicity seekers Feature + privacy balance GA replacement Set-and-forget Terminal lovers

Quick takes

Matomo is the closest to a full Google Analytics replacement. It can do heatmaps, session recordings, funnels, A/B testing, and e-commerce tracking. But it's also the most complex to run, and its PHP + MySQL stack feels dated compared to the newer options. If you need GA-level features with self-hosting, Matomo is your answer. If you don't need all that, it's overkill.

Fathom is privacy-focused and polished, but it's SaaS-only now — the self-hosted open source version is no longer maintained. If you want self-hosting, Fathom is off the table.

GoAccess is a completely different animal. It analyzes your web server's access logs directly — no tracking script, no JavaScript, no database. It runs in the terminal or generates a static HTML report. It's brilliant for quick server-level analytics and has essentially zero overhead, but it can't track events, doesn't understand SPAs, and the UX is spartan.

Umami and Plausible are the two strongest options for privacy-focused, self-hosted web analytics. Choose Umami for lower resource usage and simplicity. Choose Plausible for more advanced features like funnels and revenue tracking.

Tips for Production Use

Use a custom domain for the tracking script

Ad blockers often target known analytics domains. If you run Umami on analytics.yourdomain.com, some visitors will block requests to it. Using a subdomain of your own site (like stats.yourdomain.com) or proxying the script through your main domain reduces this.

Reverse proxy with Caddy

Put Umami behind a reverse proxy with automatic HTTPS. With Caddy:

analytics.yourdomain.com {
    reverse_proxy localhost:3000
}

Caddy handles Let's Encrypt certificates automatically.

Reverse proxy with Nginx

server {
    listen 443 ssl http2;
    server_name analytics.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/analytics.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/analytics.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Proxy the script through your own domain

To further reduce ad blocker interference, you can proxy the Umami script through your own site. In Nginx:

# Add to your main site's Nginx config
location /stats/script.js {
    proxy_pass https://analytics.yourdomain.com/script.js;
    proxy_set_header Host analytics.yourdomain.com;
}

Then reference the proxied script in your HTML:

<script defer src="/stats/script.js"
  data-website-id="your-website-id"></script>

This makes the analytics script appear to come from your own domain, which most ad blockers will allow.

Using the Umami API

Umami has a REST API for extracting data programmatically. Authenticate with a token, then query any metric:

# Get an authentication token
TOKEN=$(curl -s -X POST https://analytics.yourdomain.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"your-password"}' | jq -r '.token')

# Get pageviews for the last 7 days
curl -s "https://analytics.yourdomain.com/api/websites/{website-id}/pageviews?startAt=$(date -d '7 days ago' +%s)000&endAt=$(date +%s)000&unit=day" \
  -H "Authorization: Bearer $TOKEN"

The API is useful for building custom dashboards, generating reports, or integrating analytics data into other tools.

Database backups

Back up your PostgreSQL database regularly. A simple cron job works:

# Add to crontab: daily backup at 3 AM
0 3 * * * docker exec umami-db-1 pg_dump -U umami umami | gzip > /backups/umami-$(date +\%Y\%m\%d).sql.gz

Data retention

Umami stores data indefinitely by default. If you want to limit storage growth, you can periodically clean old data through direct SQL queries on the database. There's no built-in retention policy in the UI, but the database is straightforward — events are stored in a website_event table with timestamps.

The Honest Take

What you give up compared to Google Analytics

Let's be direct about the gaps:

When Umami is the right choice

Despite those gaps, Umami is the right tool for a large number of use cases:

The bottom line

Umami won't replace Google Analytics for a marketing team that lives in attribution reports and conversion funnels. It's not trying to. What it does is provide the analytics that 90% of website owners actually look at — page views, traffic sources, popular pages, device breakdown — in a package that's private, fast, and simple enough that you'll actually check it.

If your current analytics workflow is "open Google Analytics, feel overwhelmed, close the tab," Umami might be exactly what you need. And since it runs on a $5 VPS with a five-minute Docker setup, trying it costs almost nothing.

Resources