# Insights and dashboards

An insight saves a question's definition, not its result. Every run recomputes it for the resolved period. A dashboard arranges saved insights and text into tiles. Both belong to the active product.

Read [Analytics](/analytics) for catalog discovery and one-off questions.

## Insight definitions

| Field | Accepted values or limits |
| --- | --- |
| `slug` | 2–64 lowercase letters, digits, or hyphens; starts with a letter or digit. Unique in the product and immutable. |
| `name`, `description` | Name up to 120 characters; optional description up to 2,000. |
| `kind` | `trend`, `funnel`, `number`, or `retention`. |
| `series` | 1–8 requests, each keyed by one capital letter such as `A`. |
| `formula` | Optional arithmetic using defined series keys, up to 500 characters. Not allowed for retention insights. |
| `window` | Absolute timestamp bounds or a relative period. |
| `grain` | `day`, `week`, or `month`; defaults to `day`. |
| `display` | `line`, `bar`, `bold_number`, or `table`; defaults to `line`. |
| `tags` | Up to 20, each up to 40 characters. |
| `target` | Optional `>=`, `<=`, or `=` comparison with a number. |

A series holds a metric query, funnel, or retention request, validated before saving. Each produces one number per bucket: a metric series cannot contain multiple metrics or group by a dimension. Use separate series for separate metrics or groups.

## Formulas and missing values

For a fictional Acme report, let `A` count all qualifying events and `B` count those from a selected source. `round(B / A * 100, 1)` expresses that source's percentage. Discover the actual entity and metric names in Acme's catalog before building either series.

Formulas accept `+`, `-`, `*`, `/`, unary minus, parentheses, numeric literals, `round(value, places)`, and `coalesce(value, fallback)`. Rounding places must be a literal integer up to 15. Unknown series keys and syntax errors are rejected when saving.

A missing operand makes the result null unless you explicitly use `coalesce`. Division by zero and overflow also return null. Do not read a null bucket as zero.

## Windows

Relative windows are `last_7d`, `last_30d`, `last_90d`, or `cycle`. The day ranges include today: `last_7d` means today and the preceding six days. Absolute windows use `from` and `to`. Buckets use whole UTC days at their finest grain.

`cycle` resolves to the platform's current configured cycle on each run. If none is configured, the run fails; check the catalog or override both bounds for the run. A saved cycle is not a permanent copy of a closed period.

A saved run may override `from`, `to`, or both, without changing the stored definition. It cannot replace the series, formula, or target. A definition can also be previewed without saving through `POST /analytics/insights/run`.

## Results

A run returns the definition, resolved window, aligned series with null gaps, evaluated formula, totals, and `target_status` (`met`, `missed`, or null). Inline runs have no stored definition. Retention results also carry cohort size and retained counts so a rate can be interpreted with its denominator.

## Retention

Retention counts subjects whose first matching cohort event falls in a bucket, then checks for a return event starting on day N.

| Input | Meaning |
| --- | --- |
| `entity` | A catalog entity. |
| `subject` | `identity` or a raw event property such as `props.customer_id`; not a declared dimension. |
| `cohort`, `return` | Filters for the starting and returning events. Empty filters mean any row. |
| `day` | N, from 1 to 365. |
| `return_window_days` | Return window beginning on day N: 1–90 days, default 7. |
| `from`, `to`, `grain` | Inclusive UTC cohort range and bucket size. |

Each subject is counted once. Identity uses the first non-null identity; a property subject is read as text. A cohort whose horizon has not elapsed has null retained counts and rates: **not yet measurable**. Totals include only measurable buckets, and `meta.unmeasurable_buckets` counts the omitted buckets. Retention reads live data rather than pre-aggregated results.

## Event properties

Where the catalog exposes a properties column, `props.<key>` can group or filter on a raw property. Keys are single-level: a dot inside the key is literal, not a nested path. Quotes and backslashes are not accepted in keys.

Property values compare as strings, including numeric and boolean filter values. Unknown dimensions or a property request on an entity without properties are rejected. Grouping or filtering by a property reads the whole range live, because pre-aggregated data does not carry those properties.

## Dashboard tiles

A dashboard has an immutable slug under the same rules as insights, a name up to 120 characters, up to 20 tags, and up to 40 tiles. Each tile has `layout` coordinates `x`, `y`, `w`, and `h` on a 12-column grid. Rows can extend downward; each tile's width and height are 1–12 cells. Tile IDs must be unique; supplied IDs are preserved, otherwise generated.

An `insight` tile refers to a saved insight ID. A `text` tile holds Markdown up to 4,000 characters. A tile can also have a title.

Running a dashboard returns the board and every tile. Each tile result is the insight result, an error with status and message, or null for text. A failing tile does not fail the entire dashboard response.

Deleting an insight still referenced by a dashboard returns `409` and names the boards. Remove the references before deleting the insight.

## Operations and app behavior

| Task | MCP tool |
| --- | --- |
| Create, list, read insights | `analytics_insight_create`, `analytics_insight_list`, `analytics_insight_get` |
| Update, delete, run insights | `analytics_insight_update`, `analytics_insight_delete`, `analytics_insight_run` |
| Create, list, read dashboards | `analytics_dashboard_create`, `analytics_dashboard_list`, `analytics_dashboard_get` |
| Update, delete, run dashboards | `analytics_dashboard_update`, `analytics_dashboard_delete`, `analytics_dashboard_run` |

These are product-scoped operations. Read requires the corresponding read permission; creating and editing require write permission. The [Analytics API reference](/reference/openapi/analytics) carries HTTP equivalents.

Reading accepts an ID or slug; updates and deletion require the ID. Lists return definitions newest first, filtered by exact `tag` and case-insensitive `q` over name or slug, combined with AND. Updates change supplied fields only; unknown fields and empty changes are rejected.

In **Analytics → Insights**, compose series, formula, window, grain, display, tags, and target. Retention definitions can be created through MCP or REST but are read-only in the app. **Dashboards** arranges insight and text tiles; opening a board runs it. Save name and tag edits by submitting them.
