Umami - A Self Hosted Privacy Focused Analytics Platform

Umami - A Self Hosted Privacy Focused Analytics Platform

Umami is a free, open source analytics alternative that's easy to self host and gives complete privacy to users.

For me, having analytics on Noted was not a priority. I was more focused on content and knew a majority of my readers were using RSS readers or other means to siphon the content from Noted 😆. The thing is, I'm completely fine with that. I myself use a FOSS desktop RSS reader for my favorite blogs because it can be tedious keeping up with them all through bookmarks.

When I finally decided I wanted to use analytics, I knew it had to be Umami. I've been using Umami on my wiki website The Homelab Wiki for a few years already. It's a perfect solution.

What I wanted from Analytics

  • Simple one page view of everything I need to know
  • Analytics software I can self host with Docker
  • Easy to setup
  • Simple navigation and implementation
  • Privacy for the users of the site

Umami is a simple, easy to use, self-hosted web analytics solution. The goal is to provide you with a friendlier, privacy-focused alternative to Google Analytics and a free, open-sourced alternative to paid solutions. Umami collects only the metrics you care about and everything fits on a single page. You can view a live demo here.

Here is a user friendly way to install Unami assuming you are already familiar with Docker and have it installed on your host machine.

  1. Install Filebrowser (if you want to cheat and not use CLI)
version: "2.1"
services:
  filebrowser:
    image: hurlenko/filebrowser:latest
    container_name: filebrowser
    environment:
      - FB_BASEURL=/f
    volumes:
      - /:/data
      - /docker/filebrowser:/config
    ports:
      - 8081:8080
    restart: unless-stopped

2. Create the schema.postgresql.sql file and place it in /docker/umami

Paste the following into the schema.postgresql.sql file.

drop table if exists event;
drop table if exists pageview;
drop table if exists session;
drop table if exists website;
drop table if exists account;

create table account (
    user_id serial primary key,
    username varchar(255) unique not null,
    password varchar(60) not null,
    is_admin bool not null default false,
    created_at timestamp with time zone default current_timestamp,
    updated_at timestamp with time zone default current_timestamp
);

create table website (
    website_id serial primary key,
    website_uuid uuid unique not null,
    user_id int not null references account(user_id) on delete cascade,
    name varchar(100) not null,
    domain varchar(500),
    share_id varchar(64) unique,
    created_at timestamp with time zone default current_timestamp
);

create table session (
    session_id serial primary key,
    session_uuid uuid unique not null,
    website_id int not null references website(website_id) on delete cascade,
    created_at timestamp with time zone default current_timestamp,
    hostname varchar(100),
    browser varchar(20),
    os varchar(20),
    device varchar(20),
    screen varchar(11),
    language varchar(35),
    country char(2)
);

create table pageview (
    view_id serial primary key,
    website_id int not null references website(website_id) on delete cascade,
    session_id int not null references session(session_id) on delete cascade,
    created_at timestamp with time zone default current_timestamp,
    url varchar(500) not null,
    referrer varchar(500)
);

create table event (
    event_id serial primary key,
    website_id int not null references website(website_id) on delete cascade,
    session_id int not null references session(session_id) on delete cascade,
    created_at timestamp with time zone default current_timestamp,
    url varchar(500) not null,
    event_type varchar(50) not null,
    event_value varchar(50) not null
);

create index website_user_id_idx on website(user_id);

create index session_created_at_idx on session(created_at);
create index session_website_id_idx on session(website_id);

create index pageview_created_at_idx on pageview(created_at);
create index pageview_website_id_idx on pageview(website_id);
create index pageview_session_id_idx on pageview(session_id);
create index pageview_website_id_created_at_idx on pageview(website_id, created_at);
create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at);

create index event_created_at_idx on event(created_at);
create index event_website_id_idx on event(website_id);
create index event_session_id_idx on event(session_id);

insert into account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true);

3. Run the Docker Compose stack and install

version: '3'
services:
  umami:
    image: ghcr.io/mikecao/umami:postgresql-latest
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://umami:[email protected]:5432/umami
      DATABASE_TYPE: postgresql
      HASH_SALT: H6ei6O1tdLNxIQLRs4Mw
    depends_on:
      - db
    restart: always
  db:
    image: postgres:12-alpine
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: umami
    volumes:
      - /docker/umami/schema.postgresql.sql:/docker-entrypoint-initdb.d/schema.postgresql.sql:ro
      - /docker/umami/db:/var/lib/postgresql/data
    restart: always
volumes:
  umami-db-data:

4. Connect to the web UI

Go to your.server.ip.here:3000 and log in using admin as the username and umami as the password.

My favorite thing about Umami is the Realtime view. It allows you to see the traffic on your website in realtime. It's fun to look at and see what people are reading in real time.

Tutorial video

Final Notes and Thoughts

Umami is a fantastic self hosted analytics solution and we value the key component of allowing the privacy of the users.

To be clear, Umami is not the only self hosted analytics option out there. There are a couple more honorable mentions that I have not tried. Post Hog and Matomo are the two I am most familiar with. I've dabbled with Matomo and it is another good solution but was a bit excessive for my needs.

Let me know what you think and what you use on your websites in the comments below!

💬 Anonymous comments are welcomed but manually approved

Great! Next, complete checkout for full access to Noted.
Welcome back! You've successfully signed in.
You've successfully subscribed to Noted.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info has been updated.
Your billing was not updated.