Skip to main content

App Utilization by User

Approved

This endpoint is approved but has not been implemented yet. See the App Usage Dashboard Spec for full context.

GET /clients/{client_id}/analytics/apps/utilization/users

Returns a paginated list of users ranked by the number of distinct apps they used during the period. Each row contains a user reference, their department, and the app count with optional comparison-period change percentage.

This endpoint powers the "Users" tab in the AI Apps and Un-Approved Apps sections of the App Usage Dashboard. It is a dimension view — for per-app metrics, use App Utilization.

Use Case

Use this endpoint to:

  • Render a users tab showing who uses the most apps
  • Identify top users of unapproved apps with is_approved=false
  • Identify top users of AI apps with category_ids=<ai_id>
  • Compare user app adoption between time periods

Path Parameters

ParameterTypeDescription
client_idstring (uuid)Unique identifier for the client organization

Query Parameters

ParameterTypeRequiredDefaultDescription
granularitystringYes-Aggregation granularity: daily, weekly, monthly, quarterly
start_datestringYes-Start of period (YYYY-MM-DD)
end_datestringYes-End of period, inclusive (YYYY-MM-DD)
compare_start_datestringNo-Comparison period start (YYYY-MM-DD). Must be provided with compare_end_date.
compare_end_datestringNo-Comparison period end, inclusive (YYYY-MM-DD). Must be provided with compare_start_date.
is_approvedbooleanNo-Filter to apps by approval status. When false, app_count reflects only unapproved apps each user interacted with.
category_idsstringNo-Comma-separated catalog category UUIDs to filter apps by
vendor_idsstringNo-Comma-separated catalog vendor UUIDs to filter apps by
department_idsstringNo-Comma-separated department UUIDs to filter users by
sort_bystringNoapp_countSort field: app_count, username
sort_orderstringNodescSort direction: asc, desc
page_sizeintegerNo50Items per page. Max: 200
cursorstringNo-Pagination cursor from a previous response

Comparison period

When both compare_start_date and compare_end_date are provided, app_count.change_pct contains the percentage change from the comparison period to the primary period. When omitted, app_count.change_pct is null.

Providing only one of the two comparison parameters returns 400.

Response

FieldTypeDescription
periodPeriodResolved date range
dataUserUtilization[]Array of user utilization objects
total_countintegerTotal number of users matching the current filters
next_cursorstring | nullCursor for the next page. null when on the last page.

Example Requests

Top users of unapproved apps, February 2026

curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/utilization/users?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&is_approved=false" \
-H "Authorization: Bearer YOUR_API_TOKEN"

Top users of AI apps with comparison

curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/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&category_ids=a7b8c9d0-e1f2-3456-abcd-789012345678" \
-H "Authorization: Bearer YOUR_API_TOKEN"

Filtered by department

curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/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 (unapproved apps)

{
"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 }
},
"department": {
"id": "d1a2b3c4-e5f6-7890-abcd-ef1234567890",
"name": "Product",
"description": "Product management and design"
},
"app_count": { "value": 6, "change_pct": 50.0, "compare_value": 4 }
},
{
"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" }
},
"department": {
"id": "e2b3c4d5-f6a7-8901-bcde-f12345678901",
"name": "Engineering",
"description": "Software development and infrastructure teams"
},
"app_count": { "value": 5, "change_pct": 25.0, "compare_value": 4 }
},
{
"user": {
"id": "u3c4d5e6-f7a8-9012-cdef-123456789012",
"username": "alex.kim",
"user_key": "alex.kim@example.com",
"last_activity": { "at": "2026-02-25T11:30:00.000Z", "desktop_at": null, "web_at": "2026-02-25T11:30:00.000Z" }
},
"department": {
"id": "f3c4d5e6-a7b8-9012-cdef-123456789012",
"name": "Marketing",
"description": null
},
"app_count": { "value": 4, "change_pct": -20.0, "compare_value": 5 }
},
{
"user": {
"id": "u4d5e6f7-a8b9-0123-defa-234567890123",
"username": "maria.garcia",
"user_key": "maria.garcia@example.com",
"last_activity": { "at": "2026-02-24T14:55:00.000Z", "desktop_at": "2026-02-24T14:55:00.000Z", "web_at": null }
},
"department": {
"id": "a4d5e6f7-b8c9-0123-defa-234567890123",
"name": "Design",
"description": "Visual and product design"
},
"app_count": { "value": 3, "change_pct": null, "compare_value": null }
},
{
"user": {
"id": "u5e6f7a8-b9c0-1234-efab-345678901234",
"username": "david.park",
"user_key": "david.park@example.com",
"last_activity": { "at": "2026-02-28T08:20:00.000Z", "desktop_at": "2026-02-28T08:20:00.000Z", "web_at": "2026-02-27T15:00:00.000Z" }
},
"department": {
"id": "b5e6f7a8-c9d0-1234-efab-345678901234",
"name": "Sales",
"description": "Revenue and business development"
},
"app_count": { "value": 2, "change_pct": 0.0, "compare_value": 2 }
}
],
"total_count": 58,
"next_cursor": "eyJsYXN0X2lkIjoidTVlNmY3YTgifQ"
}

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 }
},
"department": {
"id": "d1a2b3c4-e5f6-7890-abcd-ef1234567890",
"name": "Product",
"description": "Product management and design"
},
"app_count": { "value": 6, "change_pct": null, "compare_value": null }
}
],
"total_count": 58,
"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

FieldTypeNullableDescription
start_datestringNoStart of the primary period (YYYY-MM-DD)
end_datestringNoEnd of the primary period (YYYY-MM-DD)
compare_start_datestringYesStart of comparison period. null if no comparison requested.
compare_end_datestringYesEnd of comparison period. null if no comparison requested.

UserUtilization

FieldTypeNullableDescription
userUserRefNoLightweight user reference with identity fields
departmentDepartmentRefYesThe user's primary department. null if the user is not assigned to any department.
app_countMetricWithDeltaDtoNoDistinct apps this user interacted with during the period (scoped to any active filters)

DB source:

DTO FieldDB Aggregation
userJoined via app_usage_reports.user_idusers
departmentFirst department from user-department assignments
app_count.valueCOUNT(DISTINCT app_usage_reports.application_id) WHERE activity_date BETWEEN start_date AND end_date, grouped by user_id
app_count.change_pct((current - comparison) / comparison) * 100 using the same aggregation over the comparison date range
app_count.compare_valueThe same aggregation as app_count.value applied to the comparison date range. null when no comparison period is requested.

Pagination

This endpoint uses cursor-based pagination.

  1. Omit cursor on the first request
  2. If next_cursor is not null, pass its value as cursor on the next request
  3. Repeat until next_cursor is null

Constraints

  • Max date range: 366 days for both primary and comparison periods. Requests exceeding this return 400.
  • Comparison symmetry: Both compare_start_date and compare_end_date must be provided together, or both omitted.
  • Timezone: All dates are in the client's configured timezone.
  • granularity is required. There is no default.
  • Multi-department users: If a user belongs to multiple departments, the department field returns their first assigned department. The user appears once in the list, not once per department.

Error Responses

StatusDescription
400Invalid parameters (bad date format, range exceeds 366 days, mismatched comparison params, missing granularity, unknown sort_by value)
401Authentication required
403Insufficient permissions for this client
404Client not found
500Server error

Notes

  • When is_approved=false is provided, app_count reflects only unapproved apps the user interacted with, not their total app count.
  • When category_ids is provided, app_count reflects only apps in those categories.
  • Filters compose: ?is_approved=false&department_ids=<id> returns users in the specified department ranked by their unapproved app count.