Analytics plugin¶
dhis2w-core/plugins/analytics/ wraps DHIS2's analytics API at /api/analytics and the analytics-table management endpoint at /api/resourceTables/analytics. The analytics engine is DHIS2's aggregation pipeline — pre-computed tables behind every dashboard, pivot table, and data query.
What it exposes¶
| Operation | CLI | MCP tool |
|---|---|---|
| Aggregated query | dhis2 analytics query |
analytics_query |
| Raw (pre-aggregation) query | dhis2 analytics query --shape raw |
analytics_query (shape=raw) |
| DataValueSet-shaped output | dhis2 analytics query --shape dvs |
analytics_query (shape=dvs) |
| Trigger analytics rebuild | dhis2 maintenance refresh analytics |
maintenance_refresh_analytics |
Refresh commands live under dhis2 maintenance refresh ... — see the maintenance plugin for the full surface. This page focuses on the query side.
Dimensions and filters¶
Every analytics query is built from dimensions (rows/columns you want to see) and filters (rows/columns you want to constrain but not display).
Each dimension is a string <type>:<UID[;UID...]> or <type>:<keyword>:
| Type prefix | What it is | Example |
|---|---|---|
dx |
Data — data elements, indicators, data sets, event data | dx:fbfJHSPpUQD;cYeuwXTCPkU |
pe |
Periods | pe:LAST_12_MONTHS or pe:202401;202402 |
ou |
Organisation units | ou:ImspTQPwCqd or ou:LEVEL-2;OU_GROUP-ABC |
co |
Category option combos | co:KsP9obVY8jF |
ao |
Attribute option combos | ao:... |
Period keywords DHIS2 understands include LAST_12_MONTHS, LAST_6_MONTHS, THIS_MONTH, LAST_YEAR, THIS_QUARTER, LAST_4_QUARTERS, LAST_5_YEARS, etc.
CLI examples¶
# Simple aggregated query: one data element over the last 12 months at a specific org unit
dhis2 analytics query \
--dim dx:fbfJHSPpUQD \
--dim pe:LAST_12_MONTHS \
--dim ou:ImspTQPwCqd \
--skip-meta
# Multiple data elements + a filter
dhis2 analytics query \
--dim 'dx:fbfJHSPpUQD;cYeuwXTCPkU' \
--dim pe:LAST_12_MONTHS \
--dim ou:ImspTQPwCqd \
--filter co:KsP9obVY8jF \
--agg SUM \
--output-id-scheme NAME
# Raw data variant (no server-side aggregation)
dhis2 analytics query --shape raw \
--dim dx:fbfJHSPpUQD \
--dim pe:LAST_3_MONTHS \
--dim ou:ImspTQPwCqd
# DataValueSet shape (for pipelines that want dataValues[] output)
dhis2 analytics query --shape dvs \
--dim dx:fbfJHSPpUQD \
--dim pe:LAST_12_MONTHS \
--dim ou:ImspTQPwCqd
# Trigger a rebuild of the analytics tables (async; returns a task reference).
dhis2 maintenance refresh analytics --last-years 2
# Same, but stream notifications until the table rebuild reports completed=true.
dhis2 maintenance refresh analytics --last-years 2 --watch --interval 1 --timeout 300
# Event analytics — line-listed events in a program.
dhis2 analytics events query <PROG_UID> \
--dim pe:LAST_12_MONTHS \
--dim ou:<OU_UID> \
--stage <STAGE_UID>
# Event analytics — aggregated counts grouped by the supplied dimensions.
dhis2 analytics events query <PROG_UID> --mode aggregate \
--dim dx:<DATA_ELEMENT_UID> --dim pe:LAST_12_MONTHS --dim ou:<OU_UID>
# Enrollment analytics — line-listed enrollments.
dhis2 analytics enrollments query <PROG_UID> \
--dim pe:LAST_12_MONTHS --start-date 2026-01-01 --end-date 2026-06-30
MCP examples¶
# Aggregated query
await mcp.call_tool("analytics_query", {
"dimensions": [
"dx:fbfJHSPpUQD;cYeuwXTCPkU",
"pe:LAST_12_MONTHS",
"ou:ImspTQPwCqd",
],
"aggregation_type": "SUM",
"output_id_scheme": "NAME",
"include_num_den": True,
})
# Raw
await mcp.call_tool("analytics_query (shape=raw)", {
"dimensions": ["dx:fbfJHSPpUQD", "pe:LAST_3_MONTHS", "ou:ImspTQPwCqd"],
})
# Trigger rebuild
await mcp.call_tool("maintenance_refresh_analytics", {"last_years": 2})
Response shape¶
{
"headers": [
{"name": "dx", "column": "Data", "valueType": "TEXT", ...},
{"name": "pe", "column": "Period", "valueType": "TEXT", ...},
{"name": "ou", "column": "Organisation unit", "valueType": "TEXT", ...},
{"name": "value", "column": "Value", "valueType": "NUMBER", ...}
],
"rows": [
["fbfJHSPpUQD", "202401", "ImspTQPwCqd", "4852"],
["fbfJHSPpUQD", "202402", "ImspTQPwCqd", "4911"],
...
],
"metaData": {
"dimensions": { "dx": [...], "pe": [...], "ou": [...] },
"items": { "fbfJHSPpUQD": {"name": "Penta1 doses given"}, ... }
},
"width": 4,
"height": N
}
metaData is the item-name dictionary — use it to translate UIDs to human-readable labels. skip_meta=True strips this section for lighter payloads when the caller already knows the UIDs.
Refresh is asynchronous¶
maintenance_refresh_analytics returns a DHIS2 task reference:
Poll /api/system/tasks/ANALYTICS_TABLE/{taskId} to watch progress. A typical refresh on a small instance takes 1–5 minutes; production instances can be 30+ minutes. The analytics tables need regeneration whenever data values change beyond the last-refresh window.
Output ID schemes¶
By default, UIDs stay as UIDs in responses. Set output_id_scheme to:
UID— defaultNAME— replace UIDs with display names (human-readable)CODE— use the object's code field if setID— numeric database ID (not recommended; changes across instances)
Outlier detection¶
/api/analytics/outlierDetection flags anomalous data values against the
standard-deviation profile of their series. Three algorithms supported
upstream: Z_SCORE (default), MODIFIED_Z_SCORE (median-based, robust to
existing outliers), and MIN_MAX (hard-bound cutoffs).
# Outliers across one data set + the Kambia org unit for the last 12 months:
dhis2 analytics outlier-detection \
--data-set BfMAe6Itzgt \
--org-unit PMa2VCrupOd \
--period LAST_12_MONTHS \
--algorithm Z_SCORE --threshold 2.0 --max-results 10
# Or a narrow set of data elements over an explicit date range:
dhis2 analytics outlier-detection \
--data-element fClA2Erf6IO --data-element I78gJm4KBo7 \
--org-unit jUb8gELQApl \
--start-date 2025-01-01 --end-date 2025-12-31 \
--algorithm MODIFIED_Z_SCORE
Returns a typed OutlierDetectionResponse (OAS-generated):
.metadata has the effective algorithm + threshold + count; .outlierValues
is a list of OutlierValue entries with de, deName, pe, ou, ouName,
value, mean, stdDev, absDev, and zScore.
Tracked entity analytics¶
/api/analytics/trackedEntities/query/{TET_UID} line-lists tracked entities
of a given type, with the same dimension/filter grammar as event/enrollment
analytics.
dhis2 analytics tracked-entities query FsgEX4d3Fc5 \
--dimension ou:ImspTQPwCqd --ou-mode DESCENDANTS \
--program IpHINAT79UW \
--page-size 50 --asc created
Returns the Grid envelope with the familiar headers/rows/metaData shape.
Useful for exporting a TET slice to external BI or building a registry view;
the --asc / --desc flags sort on any response column.
Resource-table regeneration¶
Three endpoints rebuild different layers of DHIS2's analytics backing store:
| Command | Endpoint | Job type | Rebuilds |
|---|---|---|---|
dhis2 maintenance refresh analytics |
/api/resourceTables/analytics |
ANALYTICS_TABLE |
Full star schema (fact + dim tables). Also refreshes resource tables unless --skip-resource-tables. |
dhis2 maintenance refresh resource-tables |
/api/resourceTables |
RESOURCE_TABLE |
Supporting OU / category hierarchy tables only — skip the analytics star schema. |
dhis2 maintenance refresh monitoring |
/api/resourceTables/monitoring |
MONITORING |
Tables backing DHIS2's data-quality / validation-rule monitoring (validation-rule evaluation reads from these). Bundled into refresh analytics unless skipped; standalone rebuild is rarely needed. |
All three accept --watch / -w to stream the job to completion via
/api/system/tasks/{jobType}/{taskUid}. Library callers use
service.refresh_analytics / refresh_resource_tables / refresh_monitoring
— each returns a WebMessageResponse whose .task_ref() pairs with
client.tasks.await_completion for typed async waits.
Not yet exposed¶
- Measure criteria with multiple operators —
--measure-criteria EQ:42:GT:100etc. - Response format overrides —
.csv,.xml,.xlsxvariants available viaclient.analytics.stream_toin the library; not yet on the CLI.
The plugin's service.py is small; extensions land as new service functions + one CLI command + one MCP tool per.