Umami is a modern, privacy-focused alternative to Google Analytics. https://umami.is
Find a file
Arthur Sepiol 34db34759f feat: implement automatic session linking and identity stitching (#3820)
Links anonymous browser sessions to authenticated user identities, enabling unified
user journey tracking across login boundaries. This solves the "logged-out anonymous
session → logged-in session" tracking gap, providing complete funnel visibility and
accurate visitor deduplication.

## Changes

- Client-side: Persistent visitor ID in localStorage (data-identity-stitching attribute)
- Server-side: identity_link table linking visitors to distinct IDs (authenticated users)
- Query updates: getWebsiteStats now deduplicates by resolved identity
- Graceful degradation: Works in Safari private browsing and when localStorage unavailable

## Implementation Details

Uses hybrid approach combining client-side persistence with server-side linking:
- Visitor ID generated once per browser, persists across sessions
- When user logs in, identify() creates identity link
- stats queries join through identity_link to deduplicate cross-device sessions

Both PostgreSQL and ClickHouse supported with appropriate query patterns:
- PostgreSQL: normalized schema, joins through session table
- ClickHouse: denormalized with ReplacingMergeTree for deduplication

## Edge Cases Handled

- Safari private browsing: localStorage throws, visitorId undefined, no link created
- localStorage cleared: new visitorId generated, creates new link
- Multiple tabs: same visitorId shared via localStorage
- Multiple devices: one visitor can link to multiple distinct_ids
- Multiple accounts: one distinct_id can link to multiple visitors

## Test Plan

- [ ] Enable feature on test website (default enabled)
- [ ] Anonymous pageview - confirm visitor_id in events table
- [ ] Call umami.identify('user1') - confirm identity_link created
- [ ] Stats show 1 visitor (deduplicated)
- [ ] Log out, browse anonymously, stats still show 1 visitor
- [ ] Test with data-identity-stitching="false" - no visitor_id collected
- [ ] Test in Safari private browsing - no errors, gracefully skips
- [ ] Test ClickHouse: verify identity_link table populated and FINAL keyword works
- [ ] Verify retroactive: historical anonymous session attributed correctly
2025-12-03 16:54:56 +03:00
.github New docker workflow. 2025-11-07 22:41:10 -08:00
.husky Card mode for tables. 2025-10-14 13:04:14 -07:00
cypress Add test for updating a website with only shareId 2025-08-19 14:43:42 +00:00
db feat: implement automatic session linking and identity stitching (#3820) 2025-12-03 16:54:56 +03:00
docker Updated lang files. 2025-10-06 12:11:26 -07:00
podman Fixed typo in README.md 2025-04-17 19:08:25 +02:00
prisma feat: implement automatic session linking and identity stitching (#3820) 2025-12-03 16:54:56 +03:00
public Updated lang files. 2025-10-06 12:11:26 -07:00
scripts Merge pull request #3743 from Mintimate/master 2025-11-12 21:33:19 -08:00
src feat: implement automatic session linking and identity stitching (#3820) 2025-12-03 16:54:56 +03:00
.dockerignore Fixed docker build. 2025-10-06 02:12:57 -07:00
.eslintignore Removed mysql schema. 2025-05-09 22:06:39 -07:00
.eslintrc.json Redesigned overview page. 2025-08-21 03:01:37 -07:00
.gitignore chore [#3699] : fix .gitignore syntax and untrack package-lock.json 2025-11-08 22:33:22 +01:00
.prettierignore Removed mysql schema. 2025-05-09 22:06:39 -07:00
.prettierrc.json Initial commit. 2020-07-17 01:03:38 -07:00
.stylelintrc.json Updated filter bar. 2025-04-02 23:18:03 -05:00
app.json Changed HASH_SALT to APP_SECRET. 2022-12-27 21:38:23 -08:00
cypress.config.ts add api-testing to cypress tests 2025-03-12 10:32:54 -07:00
docker-compose.yml Added check for REDIS_URL. Closes #3677. 2025-11-10 21:08:55 -08:00
Dockerfile Updated Dockerfile to match current Prisma version. 2025-11-03 16:54:58 -08:00
jest.config.ts Fix test. 2025-03-31 22:49:34 -05:00
LICENSE Updated packages. 2022-12-26 20:50:55 -08:00
netlify.toml Adds @netlify/plugin-nextjs package & fixed dashboard link id 2022-10-25 15:01:49 +01:00
next-env.d.ts Redesigned overview page. 2025-08-21 03:01:37 -07:00
next.config.ts Add rewrite for script in cloud mode. 2025-10-08 16:01:47 -07:00
package.components.json Responsive everything. 2025-10-16 02:42:13 -07:00
package.json Added data-fetch-credentials attribute. Closes #3644 2025-11-13 19:42:04 -08:00
pnpm-lock.yaml Added data-fetch-credentials attribute. Closes #3644 2025-11-13 19:42:04 -08:00
pnpm-workspace.yaml Replaced __dirname usage. 2025-04-29 09:53:11 -07:00
postcss.config.js Switched to type: module. 2025-04-29 14:36:52 -07:00
README.md docs: remove underlines between bandges in README.md 2025-11-15 23:34:26 +03:00
rollup.tracker.config.js Switched to type: module. 2025-04-29 14:36:52 -07:00
tsconfig.json Converted UTM report to a view. 2025-05-20 21:25:06 -07:00
tsconfig.prisma.json Fixed outputs. 2025-09-01 16:17:55 -07:00
tsup.config.js Export metrics components. 2025-09-03 17:16:03 -07:00

Umami Logo

Umami

Umami is a simple, fast, privacy-focused alternative to Google Analytics.

GitHub Release MIT License Build Status Umami Demo


🚀 Getting Started

A detailed getting started guide can be found at umami.is/docs.


🛠 Installing from Source

Requirements

  • A server with Node.js version 18.18 or newer
  • A database. Umami supports PostgreSQL (minimum v12.14) databases.

Get the Source Code and Install Packages

git clone https://github.com/umami-software/umami.git
cd umami
pnpm install

Configure Umami

Create an .env file with the following:

DATABASE_URL=connection-url

The connection URL format:

postgresql://username:mypassword@localhost:5432/mydb

Build the Application

pnpm run build

The build step will create tables in your database if you are installing for the first time. It will also create a login user with username admin and password umami.

Start the Application

pnpm run start

By default, this will launch the application on http://localhost:3000. You will need to either proxy requests from your web server or change the port to serve the application directly.


🐳 Installing with Docker

To build the Umami container and start up a Postgres database, run:

docker compose up -d

Alternatively, to pull just the Umami Docker image with PostgreSQL support:

docker pull docker.umami.is/umami-software/umami:latest

🔄 Getting Updates

Warning

If you are updating from Umami V2, image "postgresql-latest" is deprecated. You must change it to "latest". e.g., rename docker.umami.is/umami-software/umami:postgresql-latest to docker.umami.is/umami-software/umami:latest.

To get the latest features, simply do a pull, install any new dependencies, and rebuild:

git pull
pnpm install
pnpm run build

To update the Docker image, simply pull the new images and rebuild:

docker compose pull
docker compose up --force-recreate -d

🛟 Support

GitHub Twitter LinkedIn Discord