-
Notifications
You must be signed in to change notification settings - Fork 12
Licence Activity
Availability: this feature is in
devthrough feature PR #456, but is not in the current stable release. Draft release PR #458 contains it and remains held for performance work. Do not treat the dev merge as a stable-release or scale-readiness approval.
Insights > Reports > Licence activity is a high-level explorer for leaders reviewing Microsoft 365 usage and administrators reviewing licence assignments. It starts with assigned-user counts and separate Teams, Outlook, OneDrive, SharePoint and Copilot activity distributions. It does not analyse content or prompts, buy licences, or remove assignments.
| Figure | Interpretation |
|---|---|
| Assigned users for a SKU | Distinct users currently present in that SKU's imported assignments. A person assigned two SKUs appears in both. |
| Distinct assigned users | Unique people across the selected demographic population. Do not substitute a sum of SKU assignments. |
| Workload activity | Evidence of that licence holder's activity, not proof that this particular SKU enabled it. Overlapping licences make attribution impossible. |
| Purchased or available seats | Not reported. The existing assignment tables do not establish purchased capacity. |
| Historical period | Activity in the selected reporting period compared with currently imported assignments, not proven historical licence ownership. |
These are activity estimates, not productivity, ROI or compliance measures. Low activity is a reason to investigate with the user or department, not sufficient evidence to remove a licence.
The tab stays visible even if imports are disabled. GraphUsersMetadata supplies licence-to-user assignments; when it is disabled, the page explains the prerequisite instead of displaying a misleading empty report. Enable user metadata in the installer and allow its import to complete.
Microsoft 365 workload measures use the existing GraphUsageReports import. Copilot prefers the official per-user GraphCopilotUsageReports source where it can answer the selected period, with supported imported evidence used as a fallback. Each workload identifies its source and coverage independently. A missing workload does not hide the feature.
All users already authorised to sign in to the portal can see aggregate licence activity and export its aggregate snapshot. Individual users and exports containing individual users additionally require the LicenceActivity.ReadUsers application role. The server enforces this; it is not just a hidden button.
To grant that role:
- Open the Entra app registration used for the web portal's sign-in (the runtime application, not the installer's separate application).
- Under App roles, create an enabled role with a descriptive display name, Users/Groups as the allowed member type, and the exact value
LicenceActivity.ReadUsers. Do not replace existing roles or alter the application's other settings. - Open the corresponding Enterprise application > Users and groups and assign that role to the administrators who should inspect individual licence activity.
- Have those administrators sign out of the portal and sign back in so the new role is present in their sign-in token.
This is an additional permission on the new licence-activity user endpoints and exports only. It does not separate the rest of Insights from Administration or change existing portal permissions. Continue restricting portal access as described in Verify and Security model.
No database migration or installer saved-config schema change is required. The optional role assignment above is an Entra configuration step, not an installer JSON property.
Start with the SKU overview. Assigned-user counts show the size of each population; each workload has its own distribution rather than an opaque combined score. A licence with zero assigned users still appears.
Department and country filters use imported user metadata. An unknown demographic means that metadata was not supplied; it is not a real department or country. Breakdowns count distinct people, not the sum of their licence assignments. Large demographic lists are bounded, with truncation indicated.
Select a licence to inspect its users if you have the additional role. Choose the workload to rank, and the number of most-active and least-active users. The two lists use the selected workload only. Browse the rest of the population with server-side sorting and paging.
Search uses UPN or email, not display name. The current user importer and schema do not store Graph user display names. The explorer does not invent names from email addresses. Department, country and licence names retain their existing Unicode support.
The requested most/least count and page size are each limited to 1-100 users. Search is limited to 100 characters. Pages are numbered 1-10,000. Demographic breakdowns show the top 50 departments and top 50 countries by assigned users, and the department/country filter lists retain at most 100 options per dimension across a session, saying so when that limit truncates them. Ties are ordered deterministically so changing pages does not arbitrarily reshuffle equal results.
Date ranges are inclusive UTC dates, from 7 to 180 days, ending before the current UTC date. The earliest accepted date is 1753-01-01. Presets are convenient starting points; a custom selection is validated, not silently rounded to a preset.
The default is the last four fully settled weeks: 28 days ending on the latest Sunday at least three days before today in UTC. This gives healthy imports a chance to provide complete evidence instead of defaulting to the still-arriving current week. Custom dates remain exactly the dates you choose.
The 7-, 28-, 90- and 180-day presets all end on that same settled Sunday and contain exactly the stated number of inclusive dates. The 90- and 180-day options are not rounded to whole weeks. The settlement delay is a default reporting boundary, not a guarantee that every workload has complete coverage.
If the available Copilot evidence consists only of weekly D7 snapshots, an exact 90- or 180-day range can leave a leading portion uncovered because it begins part-way through a week. Healthy imports can therefore still produce partial or unknown Copilot evidence and no least-active ranking. Read the selected source and effective coverage; the report must not silently replace the requested range with a shorter whole-week period.
Changing a licence, demographic filter, ranking or search preserves the reporting-period selection.
The requested range is not a promise that every source has complete data for it. Read the workload coverage alongside the distributions:
| Coverage information | Why it matters |
|---|---|
| Effective from/through dates | The evidence actually used may cover less than the requested interval. |
| Source and aggregation granularity | A reporting snapshot is not a precise series of daily events. |
| Report period and sampled dates | Graph can return rolling periods; overlapping snapshots must not be summed. |
| Import freshness and lag | Usage reports are delayed. Unsettled or missing snapshots are not zero usage. |
| Identity matching | Concealed or otherwise unmatchable report identities cannot reliably be joined to assignments. |
The Microsoft 365 measures reuse the settled reporting-window approach used by the other Reports views, including the usage-report settlement lag. Supporting action counts are snapshot averages, not manufactured daily totals.
A snapshot arriving earlier than the end of a requested week portion is only evidence as of that snapshot. Likewise, a snapshot present for other users does not prove that a particular person was included. Complete matching per-user evidence is required for a measured zero and the least-active list. Positive partial evidence can still appear in the most-active list, clearly labelled as partial.
Bands describe the share of reporting samples with activity:
| Band | Definition |
|---|---|
| High | At least 75% of the required samples show activity. |
| Moderate | At least 25%, but less than 75%. |
| Low | Some activity, but less than 25%. |
| No activity | Complete matching evidence, with no activity in the measured samples. This is a measured zero, and it is the only zero-like state eligible for the least-active list. |
| Unknown | The evidence needed to classify that user is incomplete or unavailable. |
Inspect each workload's sample counts, source and coverage before comparing populations. These thresholds describe frequency in the available reporting samples, not a common unit of work across Microsoft 365 products.
The page distinguishes disabled imports, not-yet-imported data, missing coverage, unmatchable identities, and partial evidence from measured zero. Missing evidence must not place a person in the least-active list. An event-only source can prove that an event was observed; absence of an event alone does not establish complete collection or inactivity.
Use Export to Excel to download a real .xlsx workbook containing the displayed aggregate snapshot, source coverage, demographic breakdowns, date/filter settings and interpretation notes.
For an authorised administrator with a user view loaded, the workbook also contains the current most-active list, least-active list and browse page, with their supporting workload evidence. It is deliberately bounded: it does not silently export the entire directory or rerun a different query.
The workbook records the generation time of the overview and user results. It is built from those cached results, not from a fresh database query that could disagree with the screen. Treat a downloaded workbook containing individual users as organisational data and apply your usual access and retention controls.
If either snapshot has expired, been evicted or is no longer available after a web-process restart, refresh the current view and export again. The endpoint returns an explicit error rather than a workbook containing changed or incomplete results.
Overview results have a maximum five-minute cache lifetime; user pages have a maximum two-minute lifetime and never outlive their overview. Both caches are bounded and belong to the web process. Results can therefore expire earlier because of eviction or process restart. In a multi-instance App Service, retain request affinity for a browser's snapshot requests.
The explorer aggregates, ranks, searches and pages in SQL. It does not load the entire user-by-licence population into the browser or web process and does not run Copilot Adoption analysis once per SKU.
Identical cold requests share work. A browser cancelling an obsolete request cancels only its own wait, not another caller's shared query. At most four shared report loads are admitted concurrently per web process; a load can issue multiple SQL commands. A 30-second response/publication deadline begins when a shared run is admitted; a late result is rejected and cancellation is requested independently of the loader's cooperation. A timed-out operation keeps its concurrency slot until its SQL resources have finished cancelling or disposing, rather than admitting unlimited replacement queries. Completed JSON responses are capped at 1 MiB.
Four report loads does not mean four SQL commands. One overview can hold one eligibility connection plus five workload connections. A process-wide limit allows six concurrent overview worker commands; user-page loads use one connection and command each. With the four-report admission limit, the code-derived mixed-load ceilings are ten open connections and eight active commands. These limits cover licence activity only, not other portal queries or importers.
The page does not use long-running 202 analysis polling. A failed or overloaded query returns a visible retryable error (503 with Retry-After); failure is not presented as an empty successful report. ASP.NET session state remains disabled.
The real Azure review used the same synthetic 300,000-user, 50-SKU database at S4 / 200 DTUs and S6 / 400 DTUs, with 7.8 million rows in each workload activity table. Neither tier passed full acceptance. Each SQL command retained its 20-second timeout, and each shared response retained its 30-second publication deadline.
| Observed result | S4 / 200 DTUs | S6 / 400 DTUs |
|---|---|---|
| Instrumented 7-day HTTP overview median | 11.937 seconds | 7.341 seconds |
| Exact 180-day HTTP overview | 503 / timeout | 503 / timeout |
| Completed cold/warm user pairs | 750 of 1,500 required | 750 of 1,500 required |
| Managed/private process growth | 135.4 / 146.6 MiB | 152.4 / 160.5 MiB |
The full narrow-window user matrix, search, paging, demographic views, concurrency and Excel cases completed. The first wide overview stopped the remaining matrix, and memory growth exceeded the predeclared 128-MiB bound. The first uninstrumented 7-day adapter repeat also timed out at both tiers, so the instrumented narrow medians are not a guarantee that choosing seven days avoids the problem.
This was the real API/cache/SQL/export logic with an in-process HTTP client and server, including the SQL network path. It was not an IIS/App Service/Entra deployment test; SQL buffer/plan caches were retained and uncontrolled. Actual plans identified aggregation spills and expensive access paths. No permanent index, schema change, narrower date range or larger production timeout was introduced.
Treat a retryable error as a real unavailable result, not evidence of zero activity. Do not repeatedly retry a wide window and assume a larger timeout or SKU will fix it. The current measured limitations and required follow-up are tracked in draft release PR #458. The disposable benchmark database and all dedicated Azure resources were deleted and independently verified absent after the review.
Draft PR #457 contains additional query improvements and reproduced correctness fixes: consistent Copilot period-counter interpretation across aggregate and individual views, duplicate report-day handling, and preserving a valid browse page when an expired overview is renewed. It also moves to the last valid page if the renewed population has shrunk. These changes are not yet merged into dev or included in draft release #458, and were not tested by the Azure baseline review above. Passing correctness tests and code reviews do not remove the target-tier performance and memory hold.
Privacy-safe LicenceActivityLifecycle events identify a run, stage and duration without logging query text, user payloads, search terms or filter values. Use these alongside SQL execution diagnostics to distinguish query execution, materialisation, projection, publication and web-host shutdown. Do not enable broad SQL/parameter logging against tenant data for this report.
- Home
- What data is collected
- The web portal
- Licence activity
- Copilot data & stats
- Architecture & costs
- App registrations setup
- Install with the installer
- Manual installation
- Private endpoints (optional)
- Certificate authentication (optional)
- Enable CSP for AITracker
- Verify the deployment
- Legacy SPO web setup