App Utilization by Category
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/categories
Returns a paginated list of catalog categories ranked by app or user count for the requested period. Each row contains a category reference alongside aggregate metrics (app count, user count) and optional comparison-period change percentages.
This endpoint powers the "Categories" 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 categories tab showing which app categories are most used
- Filter to AI-only categories with
category_ids - Filter to unapproved app categories with
is_approved=false - Compare category distribution between time periods
Path Parameters
| Parameter | Type | Description |
|---|---|---|
client_id | string (uuid) | Unique identifier for the client organization |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
granularity | string | Yes | - | Aggregation granularity: daily, weekly, monthly, quarterly |
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. |
is_approved | boolean | No | - | Filter to apps by approval status |
category_ids | string | No | - | Comma-separated catalog category UUIDs. When provided, only apps matching these categories are included, and the response groups by all categories those apps belong to (which may include categories not in the filter). |
vendor_ids | string | No | - | Comma-separated catalog vendor UUIDs to filter by |
department_ids | string | No | - | Comma-separated department UUIDs to scope usage data to |
sort_by | string | No | app_count | Sort field: app_count, user_count, name |
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 |
Comparison period
When both compare_start_date and compare_end_date are provided, change_pct fields contain the percentage change from the comparison period to the primary period. When omitted, all change_pct fields are null.
Providing only one of the two comparison parameters returns 400.
Response
| Field | Type | Description |
|---|---|---|
period | Period | Resolved date range |
data | CategoryUtilization[] | Array of category utilization objects |
total_count | integer | Total number of categories matching the current filters |
next_cursor | string | null | Cursor for the next page. null when on the last page. |
Example Requests
AI app categories for February 2026
curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/utilization/categories?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&category_ids=a7b8c9d0-e1f2-3456-abcd-789012345678" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Unapproved app categories with comparison
curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/utilization/categories?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&compare_start_date=2026-01-01&compare_end_date=2026-01-31&is_approved=false" \
-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": [
{
"category": {
"id": "a7b8c9d0-e1f2-3456-abcd-789012345678",
"name": "CRM"
},
"app_count": { "value": 4, "change_pct": 33.3, "compare_value": 3 },
"user_count": { "value": 28, "change_pct": 12.0, "compare_value": 25 }
},
{
"category": {
"id": "b8c9d0e1-f2a3-4567-bcde-901234567890",
"name": "Communication"
},
"app_count": { "value": 3, "change_pct": 0.0, "compare_value": 3 },
"user_count": { "value": 22, "change_pct": -5.0, "compare_value": 23 }
},
{
"category": {
"id": "c9d0e1f2-a3b4-5678-cdef-012345678901",
"name": "Development"
},
"app_count": { "value": 2, "change_pct": 100.0, "compare_value": 1 },
"user_count": { "value": 15, "change_pct": null, "compare_value": null }
}
],
"total_count": 5,
"next_cursor": null
}
Without comparison period
{
"period": {
"start_date": "2026-02-01",
"end_date": "2026-02-28",
"compare_start_date": null,
"compare_end_date": null
},
"data": [
{
"category": {
"id": "a7b8c9d0-e1f2-3456-abcd-789012345678",
"name": "CRM"
},
"app_count": { "value": 4, "change_pct": null, "compare_value": null },
"user_count": { "value": 28, "change_pct": null, "compare_value": null }
}
],
"total_count": 5,
"next_cursor": "eyJsYXN0X2lkIjoiYTdiOGM5ZDAifQ"
}
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. |
CategoryUtilization
| Field | Type | Nullable | Description |
|---|---|---|---|
category | CatalogCategory | No | Category identity ({ id, name }) |
app_count | MetricWithDeltaDto | No | Distinct apps in this category with activity during the period |
user_count | MetricWithDeltaDto | No | Distinct users who used apps in this category during the period |
An app can belong to multiple categories. When this happens, the app is counted once per category it belongs to. app_count values across all rows may therefore sum to more than the total distinct app count.
DB source:
| DTO Field | DB Aggregation |
|---|---|
category | catalog_categories joined via catalog_application_catalog_categories |
app_count.value | COUNT(DISTINCT application_id) grouped by category, filtered to activity_date within the period |
user_count.value | COUNT(DISTINCT user_id) grouped by category, filtered to activity_date within the period |
*.change_pct | ((current - comparison) / comparison) * 100 using the same aggregations over the comparison date range |
*.compare_value | The same aggregation as *.value applied to the comparison date range. null when no comparison period is requested. |
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 | Client not found |
| 500 | Server error |
Related Endpoints
- App Utilization -- Paginated per-app metrics table
- App Utilization Users -- Users dimension view
- App Utilization Departments -- Departments dimension view
- App Utilization Summary -- Aggregate card counts