# Widget query language

Reference for the text syntax describing a widget's data: measures, conditions, grouping, period, sorting and functions.

> **Access:** edit right on the dashboard. See [Configure a widget](https://docs.cisapp.eu/en/reporting/widgets) for the editor. The editor labels are not yet translated into English; the query syntax is the same in every language.

## Write a query as text

1. In the widget editor, find the query row (**a**, **b**…).
2. Switch from **Form** to **Code**.
3. Type the query. The editor offers **Suggestions** (measures, data, clauses, fields, values) and flags errors with their position.

The text describes the whole query and is equivalent to the form: you can switch between them without losing anything. The query is applied as soon as it is valid. The **Action plans** selector is only set in the form.

```
count(ticket) where status IN (TODO, BLOCKED) by priority split assignee
```

## Structure

A query starts with `measure(data)`, followed by clauses, in any order and each at most once.

| Clause | Meaning | Example |
|---|---|---|
| `where …` | Conditions on the counted items. | `where status != DONE` |
| `of …` | With `percent`: share of items matching the condition. | `percent(riskMeasure) of status = VERIFIED` |
| `by field` | Group. For a date: `by field:day`, `week`, `month`, `quarter` or `year`. | `by createdAt:month` |
| `split field` | Split by a second field. | `split assignee` |
| `columns a, b` | With `list`: list columns (maximum 8). | `columns title, owner` |
| `during …` | Period: `last7d`, `last30d`, `last90d`, `last12m`, `ytd`, `all`, or `"2026-01-01" to "2026-03-31"`. | `during last12m` |
| `on field` | Date field the period applies to. | `on dueDate` |
| `sort …` | Sorting: `value` or `key` for a grouping, a field for a list, then `asc` or `desc`. | `sort value desc` |
| `limit n` | Maximum number of rows or groups (maximum 200). | `limit 10` |

## Measures

| Measure | Meaning |
|---|---|
| `count(ticket)` | Number of items. |
| `sum`, `avg`, `min`, `max`, `median` | Calculation on a numeric field: `avg(vendor.criticality)`. |
| `distinctCount(ticket.assignee)` | Number of distinct values. |
| `percent(ticket)` | Percentage, with the `of` clause. |
| `list(ticket)` | List of items, with the `columns` clause. |

## Data

| Code | Data |
|---|---|
| `vendor` | Vendors |
| `risk`, `riskMeasure` | Risks, treatment measures |
| `incident` | Incidents |
| `control`, `evidence` | Controls, evidence |
| `exemption` | Exemptions |
| `evaluation` | Assessments |
| `asset`, `finding` | Assets, vulnerabilities |
| `application` | Applications |
| `scope` | Activities |
| `processingActivity` | GDPR processing activities |
| `connector` | Connectors |
| `project`, `ticket` | Action plans, tasks |

Available data depends on the modules in your plan.

## Conditions

The `where` and `of` clauses contain conditions, combined with `AND`, `OR`, `NOT` and parentheses. `AND` takes precedence over `OR`.

```
criticality >= 3 AND status = ACTIVE AND (cf."SSO" = false OR cf."SSO" IS EMPTY)
```

| Operator | Meaning | Example |
|---|---|---|
| `=` `!=` | Equal, different. | `status = ACTIVE` |
| `>` `>=` `<` `<=` | Comparison of numbers or dates. | `criticality >= 3` |
| `~` | Contains (text). | `name ~ "bank"` |
| `IN (…)` `NOT IN (…)` | One of, not one of. | `status IN (ACTIVE, ONBOARDING)` |
| `ALL (…)` | Contains all values (multi-value fields). | `tags ALL ("critical", "EU")` |
| `BETWEEN … AND …` | Between two values. | `dueDate BETWEEN 2026-01-01 AND 2026-03-31` |
| `IS EMPTY` `IS NOT EMPTY` | Empty, filled in. | `assignee IS EMPTY` |

Available operators depend on the field type. A query holds at most 20 conditions and 4 levels of parentheses.

## Fields and values

- **Fields**: use the technical name offered by suggestions (`status`, `criticality`, `assignee`, `dueDate`…). A custom field is written `cf."Field name"`.
- **Text** in quotes: `"SSO rollout"`.
- **Numbers**: `3`, `0.5`. **Booleans**: `true`, `false`. **Dates**: `2026-03-31`.
- **Fixed values** (status, type…): the code or the label; suggestions show the label.
- **References** (user, team, action plan, vendor): the name in quotes, for example `project = "SSO rollout"`. CISAPP stores the identifier: the widget keeps working if the item is renamed.

## Functions

| Function | Value |
|---|---|
| `me()` | The user viewing the dashboard. |
| `myTeams()` | Their teams. |
| `now()` | Now; `now(-30d)` 30 days ago (`d` days, `w` weeks, `m` months, `y` years). |
| `startOf(month)` | Start of the period: `day`, `week`, `month`, `quarter`, `year`. |

With `me()` or `myTeams()`, each reader sees their own figures. Such a widget cannot track history.

## Examples

```
count(ticket) where assignee = me() AND status != DONE by priority
percent(riskMeasure) where status != PLANNED of dueDate < now()
avg(vendor.criticality) by createdAt:month during last12m
list(risk) columns title, owner, residualCriticality where open = true sort residualScore desc limit 10
count(ticket) where createdAt >= startOf(month)
```

## Expected outcome

The query is accepted with no error message, the widget preview shows the expected data, and switching to **Form** shows the same settings.

## Common issues

| Error | Cause |
|---|---|
| Unknown field | Typo, or deleted custom field. |
| Unclosed quote | A quoted text is not terminated. |
| Unknown value | The value does not exist for this field. |
| Incomplete query | The query stops in the middle of a clause or condition. |
| Unknown measure | The query must start with a measure: `count(…)`, `avg(…)`… |
| Unknown data | The name in parentheses is not one of the data codes above. |
| Measure needs a field | `sum`, `avg`, `min`, `max`, `median` and `distinctCount` apply to a field: `avg(vendor.criticality)`. |
| Field not usable in `by` | This field cannot be used to group, split, sort or display as a column. |
| Clause not available | `of` goes with `percent`, `columns` with `list`; a list has no `by` or `split`. |
| Clause appears twice | Each clause is written only once. |
| Operator not available for the field | Choose an operator suited to the field type. |
| Too many conditions / nested parentheses | At most 20 conditions and 4 levels. |
