App Utilization Users for One App
This endpoint is approved but has not been implemented yet.
GET /clients/{client_id}/analytics/apps/{app_id}/utilization/users
Returns a paginated list of users for one specific app, ranked by usage within the requested period. This is the per-app user breakdown companion to App Utilization Detail.
Use this endpoint for both the "Top App Users" preview and the full "All Users" drawer on an app detail page. "Top users" is not a separate route: request the same endpoint with a small page_size such as 5.
Data source is app_usage_reports, scoped to one app and aggregated by user over the requested period.
Use Case
Use this endpoint to:
- Show the top users for one app on the app detail page
- Drive the full paginated user list for one app
- Compare each user's average time in the app to a prior period
- Filter the app's user list to one or more departments
Path Parameters
| Parameter | Type | Description |
|---|---|---|
client_id | string (uuid) | Unique identifier for the client organization |
app_id | string (uuid) | Unique identifier for the application |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
granularity | string | Yes | - | Aggregation granularity: daily, weekly, monthly, quarterly. Determines how avg_time_ms_per_day is computed. |
start_date | string | Yes | - | Start of period (YYYY-MM-DD) |
end_date | string | Yes | - | End of period, inclusive (YYYY-MM-DD) |
compare_start_date | string | No | - | Comparison period start (YYYY-MM-DD). Must be provided with compare_end_date. |
compare_end_date | string | No | - | Comparison period end, inclusive (YYYY-MM-DD). Must be provided with compare_start_date. |
department_ids | string | No | - | Comma-separated department UUIDs to scope usage data to |
sort_by | string | No | avg_time | Sort field: avg_time, avg_time_change, days_active, username |
sort_order | string | No | desc | Sort direction: asc, desc |
page_size | integer | No | 50 | Items per page. Max: 200 |
cursor | string | No | - | Pagination cursor from a previous response |
The singular form department_id is accepted as a deprecated alias. Use the plural form for new integrations.
Comparison period
When both compare_start_date and compare_end_date are provided, avg_time_ms_per_day.change_pct contains the percentage change from the comparison period to the primary period. When omitted, avg_time_ms_per_day.change_pct is null.
Providing only one of the two comparison parameters returns 400.
Response
| Field | Type | Description |
|---|---|---|
period | Period | Resolved date range |
data | AppUserUtilization[] | Array of per-user utilization rows for this app |
total_count | integer | Total number of users matching the current filters |
next_cursor | string | null | Cursor for the next page. null when on the last page. |
Example Requests
Top 5 users for one app
curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/f1a2b3c4-d5e6-7890-abcd-ef1234567890/utilization/users?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&page_size=5" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Full list with month-over-month comparison
curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/f1a2b3c4-d5e6-7890-abcd-ef1234567890/utilization/users?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&compare_start_date=2026-01-01&compare_end_date=2026-01-31&sort_by=avg_time_change&sort_order=desc" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Scoped to a department
curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/f1a2b3c4-d5e6-7890-abcd-ef1234567890/utilization/users?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&department_ids=d1a2b3c4-e5f6-7890-abcd-ef1234567890" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Example Responses
With comparison period
{
"period": {
"start_date": "2026-02-01",
"end_date": "2026-02-28",
"compare_start_date": "2026-01-01",
"compare_end_date": "2026-01-31"
},
"data": [
{
"user": {
"id": "u1a2b3c4-d5e6-7890-abcd-ef1234567890",
"username": "james.wilson",
"user_key": "james.wilson@example.com",
"last_activity": {
"at": "2026-02-28T17:42:00.000Z",
"desktop_at": "2026-02-28T17:42:00.000Z",
"web_at": null
}
},
"avg_time_ms_per_day": { "value": 6060000, "change_pct": 12.5, "compare_value": 5386666 },
"days_active": 24
},
{
"user": {
"id": "u2b3c4d5-e6f7-8901-bcde-f12345678901",
"username": "sarah.chen",
"user_key": "sarah.chen@example.com",
"last_activity": {
"at": "2026-02-28T16:10:00.000Z",
"desktop_at": "2026-02-28T16:10:00.000Z",
"web_at": "2026-02-27T09:00:00.000Z"
}
},
"avg_time_ms_per_day": { "value": 5520000, "change_pct": -4.1, "compare_value": 5756000 },
"days_active": 21
}
],
"total_count": 18,
"next_cursor": "eyJsYXN0X2lkIjoidTJiM2M0ZDUifQ"
}
Without comparison period
{
"period": {
"start_date": "2026-02-01",
"end_date": "2026-02-28",
"compare_start_date": null,
"compare_end_date": null
},
"data": [
{
"user": {
"id": "u1a2b3c4-d5e6-7890-abcd-ef1234567890",
"username": "james.wilson",
"user_key": "james.wilson@example.com",
"last_activity": {
"at": "2026-02-28T17:42:00.000Z",
"desktop_at": "2026-02-28T17:42:00.000Z",
"web_at": null
}
},
"avg_time_ms_per_day": { "value": 6060000, "change_pct": null, "compare_value": null },
"days_active": 24
}
],
"total_count": 18,
"next_cursor": "eyJsYXN0X2lkIjoidTFhMmIzYzQifQ"
}
Empty Result
{
"period": {
"start_date": "2026-02-01",
"end_date": "2026-02-28",
"compare_start_date": null,
"compare_end_date": null
},
"data": [],
"total_count": 0,
"next_cursor": null
}
Period
| Field | Type | Nullable | Description |
|---|---|---|---|
start_date | string | No | Start of the primary period (YYYY-MM-DD) |
end_date | string | No | End of the primary period (YYYY-MM-DD) |
compare_start_date | string | Yes | Start of comparison period. null if no comparison requested. |
compare_end_date | string | Yes | End of comparison period. null if no comparison requested. |
AppUserUtilization
| Field | Type | Nullable | Description |
|---|---|---|---|
user | UserRef | No | Lightweight user reference with identity and last-activity fields |
avg_time_ms_per_day | MetricWithDeltaDto | No | Average active time in milliseconds per day for this user within this app and period |
days_active | integer | No | Number of distinct days in the primary period where this user used the app |
DB source:
| DTO Field | DB Aggregation |
|---|---|
user | Joined via app_usage_reports.user_id → UserRef fields from users |
avg_time_ms_per_day.value | SUM(total_active_ms) / COUNT(DISTINCT activity_date) for this app + user within the primary period |
avg_time_ms_per_day.change_pct | ((current - comparison) / comparison) * 100 using the same aggregation over the comparison period |
avg_time_ms_per_day.compare_value | Same aggregation as value applied to the comparison period. null when no comparison period is requested. |
days_active | COUNT(DISTINCT activity_date) for this app + user within the primary period |
Pagination
This endpoint uses cursor-based pagination.
- Omit
cursoron the first request - If
next_cursoris notnull, pass its value ascursoron the next request - Repeat until
next_cursorisnull
Constraints
- Max date range: 366 days for both primary and comparison periods. Requests exceeding this return
400. - Comparison symmetry: Both
compare_start_dateandcompare_end_datemust be provided together, or both omitted. - Timezone: All dates are in the client's configured timezone.
granularityis required. There is no default.
Error Responses
| Status | Description |
|---|---|
| 400 | Invalid parameters (bad date format, range exceeds 366 days, mismatched comparison params, missing granularity, unknown sort_by value) |
| 401 | Authentication required |
| 403 | Insufficient permissions for this client |
| 404 | App or client not found |
| 500 | Server error |
Example Error Response
{
"error": {
"code": "invalid_parameter",
"message": "Unknown sort_by: avgDailyTime. Valid values: avg_time, avg_time_change, days_active, username",
"details": {
"sort_by": "avgDailyTime"
}
}
}
Notes
- Use
page_size=5to render a "Top App Users" preview. Use the same endpoint with normal pagination for the full list. days_activeis a primary-period value only. It does not useMetricWithDeltaDto.- When
department_idsis provided, only users in those departments are included.
Related Endpoints
- App Utilization Detail -- Period-level summary metrics for this app
- App Activity -- Daily time-series for this app
- Get User -- Full user profile for a selected user