APM Tips

KQL · usage

Daily active users and sessions

Distinct users and sessions per day across requests and page views for the last 30 full days, charted, with notes on what the IDs measure.

Updated

requestspageViews usage

let lookback = 30d;
union requests, pageViews
| where timestamp >= startofday(ago(lookback)) and timestamp < startofday(now())
| where isnotempty(user_Id)
| summarize
    users = dcount(user_Id),
    sessions = dcount(session_Id)
    by bin(timestamp, 1d)
| order by timestamp asc
| render timechart

Returns: One point per UTC day for the last 30 complete days with the number of distinct user IDs and distinct session IDs seen on requests and page views.

Pitfalls

  • Users are anonymous IDs kept in a browser cookie. One person on two browsers is two users, and clearing cookies makes a new one.
  • API apps called by other services rarely have a user_Id at all, so their traffic drops out at the isnotempty filter. That is correct: they have no users to count.
  • dcount() is an estimate on large sets and can't be weighted by itemCount. Under heavy sampling, users with very few requests can be missed entirely.
  • A distinct count per day doesn't add up across days: monthly active users is its own query, not the sum of the daily numbers.

How it works

“How many people use this?” is the question every product owner asks of the monitoring team. Application Insights can answer it from the user and session IDs on each item, as long as you know what those IDs measure.

Line by line

  • let lookback = 30d; covers a month of complete UTC days; the time filter starts at midnight 30 days ago and stops at midnight today, so no partial day drags the end of the line down.
  • union requests, pageViews reads both tables. Page views come from the browser; requests carry the same IDs when the server picks them up, so a user who only calls your API from a single-page app is still counted.
  • where isnotempty(user_Id) drops items without a user ID, such as calls from other services.
  • dcount(user_Id) and dcount(session_Id) count distinct IDs per day. At the default accuracy, dcount() is exact up to about 1,000 values and an estimate above that, with a documented error of 0.8% (one standard deviation).
  • render timechart draws one line for users and one for sessions.

What the numbers mean

Microsoft’s usage documentation is plain about it: users are counted by anonymous IDs stored in browser cookies, and a person using different browsers or machines, or clearing cookies, is counted more than once. A session is a period of activity that ends after half an hour of inactivity or 24 hours of continuous use. So treat these as trends, not census figures, and expect them to read higher than a sign-in count.

For a count of signed-in people instead, set the authenticated user ID and count user_AuthenticatedId. API apps without a browser need a different approach to users and sessions altogether, which the users and sessions in API apps guide covers. The JavaScript snippet guide explains where the browser IDs come from.

Variations

  • Signed-in users: replace user_Id with user_AuthenticatedId in the filter and the dcount().
  • Per page: see page views by name and country.
  • Workspace tables: use union AppRequests, AppPageViews, TimeGenerated, UserId, SessionId and UserAuthenticatedId.

Sources, checked

  1. Usage analysis with Application Insights (users, sessions and anonymous IDs)learn.microsoft.com · checked
  2. dcount() (Kusto)learn.microsoft.com · checked
  3. union operator (Kusto)learn.microsoft.com · checked
  4. Application Insights telemetry data model (session and user context)learn.microsoft.com · checked
  5. Telemetry sampling in Application Insightslearn.microsoft.com · checked