Session Analysis
Relevant source files
The following files were used as context for generating this wiki page:- src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx
- src/app/(main)/websites/[websiteId]/sessions/SessionModal.tsx
- src/queries/sql/sessions/getWebsiteSession.ts
- prisma/schema.prisma
- src/app/api/send/route.ts
- src/tracker/index.js
- src/app/(main)/websites/[websiteId]/sessions/SessionProfile.tsx
- src/queries/sql/sessions/saveSessionData.ts
Session Analysis in Umami provides a detailed view of individual user journeys on a website. It aggregates all events, including page views and custom events, into a single session, allowing for a granular understanding of user behavior, from their first interaction to their last. This feature is crucial for debugging, understanding user flows, and analyzing specific user interactions over time.
The system captures user-specific data like browser, OS, device, and location, and ties it to a sequence of events. The frontend presents this information in a comprehensive profile view, showing session statistics, user properties, and a timeline of their activity.
Data Model
The core of session analysis is built upon several key tables in the database, primarily Session, SessionData, and WebsiteEvent. These tables are defined in the Prisma schema and work together to store all information related to a user's visit.
Sources: prisma/schema.prisma
ER Diagram
This diagram shows the relationships between the main entities involved in storing session data.
Sources: prisma/schema.prisma:28-181
Session Table
The Session table stores high-level information about a user's visit. A session is uniquely identified by a combination of the website ID, IP address, and user agent, salted with the start of the month to create a consistent sessionId.
| Field | Type | Description |
|---|---|---|
id | String (UUID) | Primary key for the session. |
websiteId | String (UUID) | Foreign key linking to the Website table. |
browser | String? | The browser used during the session. |
os | String? | The operating system used. |
device | String? | The device type (e.g., desktop, mobile). |
screen | String? | The screen resolution. |
language | String? | The user's browser language. |
country | String? | Two-letter country code. |
region | String? | Region or state. |
city | String? | City. |
distinctId | String? | An optional user-provided identifier. |
createdAt | DateTime? | Timestamp of when the session was first created. |
Sources: prisma/schema.prisma:28-56, src/app/api/send/route.ts:114-116
SessionData Table
The SessionData table stores custom key-value data associated with a session, typically sent via the identify tracking call. This allows for associating custom user attributes with a session.
| Field | Type | Description |
|---|---|---|
id | String (UUID) | Primary key. |
websiteId | String (UUID) | Foreign key to the Website table. |
sessionId | String (UUID) | Foreign key to the Session table. |
dataKey | String | The key for the custom data point. |
stringValue | String? | The value if it is a string. |
numberValue | Decimal? | The value if it is a number. |
dateValue | DateTime? | The value if it is a date. |
dataType | Int | An integer representing the data type (e.g., string, number, date). |
distinctId | String? | An optional user-provided identifier. |
createdAt | DateTime? | Timestamp of creation. |
Sources: prisma/schema.prisma:161-181, src/queries/sql/sessions/saveSessionData.ts:28-36
Session Tracking and Data Flow
The process begins on the client-side with the Umami tracker script and is processed by the /api/send backend endpoint.
Client-Side Tracking
The tracker script (/tracker/index.js) is responsible for capturing user interactions and sending them to the backend.
- Initialization: On page load, the script initializes and sends an initial page view event.
- Session ID: A
sessionIdis not generated on the client. Instead, the backend generates it based on request details to ensure consistency. - Path Changes: The script hooks into
history.pushStateandhistory.replaceStateto automatically track single-page application (SPA) navigations. When a URL change is detected, a newtrackcall is made after a 300ms delay. - Event Tracking: It listens for clicks on elements with
data-umami-eventattributes to send custom events. - Identify Calls: The
window.umami.identify()function allows developers to send custom user data, which is then stored in theSessionDatatable.
Sources: src/tracker/index.js:63-74, 142-155
Backend Data Ingestion
The POST /api/send endpoint receives all tracking data. This diagram illustrates the data processing flow for a typical event.
When a request of type identify is received, the saveSessionData function is called. This function flattens the provided JSON data and upserts it into the session_data table, either creating new records or updating existing ones for the given sessionId.
Sources: src/app/api/send/route.ts:233-241, src/queries/sql/sessions/saveSessionData.ts:18-62
Frontend Display
The user interface for session analysis is primarily composed of the SessionsPage and the SessionModal, which contains the SessionProfile.
Sources: src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx, src/app/(main)/websites/[websiteId]/sessions/SessionModal.tsx
Sessions List View
The SessionsPage component provides a tabbed interface with "Activity" and "Properties".
- Activity Tab: Contains the
SessionsDataTable, which lists all recent sessions for the selected website, showing information like country, browser, OS, and last seen time. - Properties Tab: Contains the
SessionPropertiescomponent, which allows users to explore the distribution of values for custom session data properties.
Clicking on a session in the SessionsDataTable opens the SessionModal.
Sources: src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx:19-32, src/app/(main)/websites/[websiteId]/sessions/SessionProperties.tsx:12-28
Session Profile View
When a session is selected, the SessionModal displays the SessionProfile component. This component is the main hub for analyzing a single session. It fetches detailed session data using the useWebsiteSessionQuery hook, which executes the query defined in getWebsiteSession.ts.
The data fetching and display flow is as follows:
The SessionProfile is composed of several sub-components:
SessionStats: Displays key metrics for the session, such as total visits, views, events, and average visit duration.SessionInfo: Shows properties of the session like country, region, city, browser, OS, and device.SessionActivity: A timeline of all events (page views, custom events) that occurred during the session.SessionData: Lists all custom key-value properties associated with the session fromidentifycalls.
Sources: src/app/(main)/websites/[websiteId]/sessions/SessionProfile.tsx:37-56
Data Retrieval
The primary query for fetching detailed information about a single session is getWebsiteSession. This SQL query aggregates data from both the session and website_event tables to provide a comprehensive summary.
getWebsiteSession Query
This function runs a database query that joins session with website_event on session_id to calculate metrics for a specific session.
It returns a single object with the following structure:
id(session_id)distinctIdwebsiteId- Geolocation data (
country,region,city) - Technical data (
browser,os, device,screen,language)- Timestamps (
firstAt,lastAt) - Aggregated metrics (
visits,views,events,totaltime)
Here is the relational (PostgreSQL) version of the query:
select id,
distinct_id as "distinctId",
website_id as "websiteId",
browser,
os,
device,
screen,
language,
country,
region,
city,
min(min_time) as "firstAt",
max(max_time) as "lastAt",
count(distinct visit_id) as visits,
sum(views) as views,
sum(events) as events,
sum(${getTimestampDiffSQL('min_time', 'max_time')}) as "totaltime"
from (select
session.session_id as id,
session.distinct_id,
website_event.visit_id,
session.website_id,
session.browser,
session.os,
session.device,
session.screen,
session.language,
session.country,
session.region,
session.city,
min(website_event.created_at) as min_time,
max(website_event.created_at) as max_time,
sum(case when website_event.event_type = 1 then 1 else 0 end) as views,
sum(case when website_event.event_type = 2 then 1 else 0 end) as events
from session
join website_event on website_event.session_id = session.session_id
where session.website_id = {{websiteId::uuid}}
and session.session_id = {{sessionId::uuid}}
group by session.session_id, session.distinct_id, visit_id, session.website_id, session.browser, session.os, session.device, session.screen, session.language, session.country, session.region, session.city) t
group by id, distinct_id, website_id, browser, os, device, screen, language, country, region, city;
Sources: src/queries/sql/sessions/getWebsiteSession.ts:16-52