Skip to main content

Analytics Domain

The Analytics domain provides read-only endpoints for querying activity and utilization data across users, devices, and apps. It is completely separate from the identity/CRUD resource domains -- those domains own the resource definitions, this domain owns the numbers.

Endpoint pattern

Every analytics resource exposes up to five endpoint roles:

RolePath shapeReturns
Activity/{resource}/{resource_id}/activityDaily time-series for one resource. One data point per day, one metric per request.
List/{resource}s/{kind}Paginated table across all resources. { period, data, total_count, next_cursor }
Export/{resource}s/{kind}/exportFull filtered list as a downloadable file, usually CSV.
Summary/{resource}s/{kind}/summaryFlat aggregate card counts. No pagination.
Rankings/{resource}s/{kind}/rankingsNamed top-performer slots (leader, biggest increase, biggest decrease). No pagination.

Not every resource has all five. The parent route (/{kind}) is always the list — never a container. /export, /summary, and /rankings are siblings to it.

Apps example:

GET /analytics/apps/{app_id}/activity        ← time-series for one app
GET /analytics/apps/{app_id}/utilization ← period-level summary metrics for one app
GET /analytics/apps/{app_id}/utilization/users ← paginated users for one app
GET /analytics/apps/utilization ← paginated per-app metrics table
GET /analytics/apps/utilization/export ← download the same table as CSV
GET /analytics/apps/utilization/summary ← cards: apps used, discovered, dropped off
GET /analytics/apps/utilization/rankings ← top app by session count, time, users

For the full rules on each role, see the Design Guidelines and Export endpoints.

Endpoints

Apps

EndpointMethodDescription
App ActivityGETDaily activity time-series for an app
App Utilization DetailGETPeriod-level metrics for one app (unique users, active time, avg daily time, session count)
App Utilization Users for One AppGETPaginated per-user usage breakdown for one app; use page_size=5 for "Top App Users"
App UtilizationGETPaginated utilization table across all client apps (unique users, active time, session count, avg daily time); supports discovered/dropped_off filter
App Utilization ExportGETDownload the filtered App Utilization table as CSV; same filters and sort as the JSON list
App Utilization SummaryGETCard counts: total apps used, newly discovered, dropped off, plus dimension counts (categories, users, departments).
App Utilization RankingsGETTop-ranked app by session count, active time, and active users; includes biggest movers
App Utilization TimeseriesGETTime-series of app counts by classification (unused, unapproved, AI, other) for stacked bar chart
App Utilization by CategoryGETCategories ranked by app count and user count; supports is_approved and category_ids filters
App Utilization by UserGETUsers ranked by distinct app count; supports is_approved and category_ids filters
App Utilization by DepartmentGETDepartments ranked by user count and app count; supports is_approved and category_ids filters

Devices

EndpointMethodDescription
Device ActivityGETDaily activity time-series for a device

Users

EndpointMethodDescription
User ActivityGETDaily activity time-series for a user

Data Sources

Analytics endpoints aggregate from two tables depending on the resource:

ResourceSource TableGranularity
UsersheartbeatsOne row per heartbeat per user-device pair
DevicesheartbeatsSame table, scoped by device_id
Appsapp_usage_reportsOne row per user per app per day (partitioned by month)

heartbeats

The desktop agent sends periodic heartbeats. Each heartbeat is tied to a user_id, device_id, and user_device_id. Key columns:

ColumnTypeDescription
total_activity_countintegerAggregate activity count (sum of all sources below)
chrome_activity_countintegerChrome extension activity
edge_activity_countintegerEdge extension activity
firefox_activity_countintegerFirefox extension activity
desktop_activity_countintegerDesktop agent activity
web_accessibility_activity_countintegerWeb accessibility activity
generated_at_utctimestampWhen the heartbeat was generated (used for date grouping)

app_usage_reports

Daily aggregated app usage per user. Partitioned by month (app_usage_reports_2026_01, etc.).

ColumnTypeDescription
total_active_msbigintActive time in milliseconds
total_session_countbigintNumber of sessions
application_iduuidThe app being measured
user_iduuidThe user
activity_datedateThe date of activity (used for grouping)

Shared Response DTO

ActivityTimeSeries

All /activity endpoints return this shape. See individual endpoint docs for which metric values are available.

{
"metric": "activity-count",
"label": "Total Activity",
"period": {
"start_date": "2024-01-01",
"end_date": "2024-01-15"
},
"data": [
{ "date": "2024-01-01", "value": 42 },
{ "date": "2024-01-02", "value": 38 },
{ "date": "2024-01-03", "value": 0 }
]
}
FieldTypeDescription
metricstringThe metric key that was requested
labelstringHuman-readable label for the metric (e.g. "Total Activity", "Daily Users")
periodobjectDate range for this data
period.start_datestringStart date (YYYY-MM-DD)
period.end_datestringEnd date (YYYY-MM-DD)
dataDailyDataPoint[]One entry per day in the range
data[].datestringDate (YYYY-MM-DD)
data[].valuenumberMetric value for that day (0 if no activity)

value is used instead of count because not all metrics are counts -- for example, active-time returns milliseconds.

Shared Patterns

Granularity

Use granularity only on endpoints where it changes the response value or structure. See Analytics Pattern: Granularity.

Period object in responses

All aggregate analytics endpoints that accept date range + comparison parameters echo the resolved dates back in a period object. See Response Period Object.

Filter parameters: plural IDs

All filter parameters accept comma-separated UUID lists (category_ids, department_ids, vendor_ids). See Filter Parameters: Plural IDs.

Constraints

  • Max date range (activity): 90 days. Requests exceeding this return 400.
  • Max date range (aggregate): 366 days for both primary and comparison periods.
  • Zero-fill: Days with no activity return value: 0. The response always includes every date in the requested range.
  • Timezone: All dates are in the client's configured timezone.
  • One metric per request (activity): Each request returns a single metric. To display multiple metrics (e.g. a chart with a metric selector), make parallel requests.

Extensibility

New analytics types are added as sibling sub-paths. Existing endpoints are never affected:

/analytics/apps/utilization                  ← paginated per-app metrics table
/analytics/apps/utilization/summary ← collection-level dashboard cards
/analytics/apps/utilization/rankings ← top app rankings
/analytics/apps/utilization/timeseries ← time-series by classification
/analytics/apps/utilization/categories ← categories dimension view
/analytics/apps/utilization/users ← users dimension view
/analytics/apps/utilization/departments ← departments dimension view
/analytics/apps/{app_id}/utilization ← per-app utilization detail
/analytics/apps/{app_id}/utilization/users ← per-user breakdown for an app
/analytics/devices/{device_id}/performance ← CPU/RAM resource usage