> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a custom Insights dashboard

> Compose your own analytics dashboard in the Orbit console — pick widgets from the palette, lay them out on a grid, validate the layout, and share it as a signed, white-label embed link.

# Build a custom Insights dashboard

The Insights section ships one fixed hub page plus a set of purpose-built
surfaces (retention, funnels, deliverability, LLM spend, and so on). Where
those pages stop, the **Dashboard Builder** starts: it is the no-code
composition surface at Insights → Dashboard Builder
(`/insights/dashboards`) that lets you arrange the metrics that already
exist behind the per-pillar endpoints into a layout of your own, and share
that layout as a signed, embeddable link.

This guide covers the builder mechanics — the palette, the grid, widget
configuration, layout validation, and the share/embed flow. For how to
*read* the individual Insights surfaces (retention curves, journey paths,
topic intelligence, and the rest), see [Read the Insights
dashboards](/guides/insights-dashboards).

## What a widget is

Every widget in the palette maps to one **read-only** metric endpoint the
API already serves — message volume, deliverability, voice quality, CDP
health, agent QA, LLM spend, burn rate, carbon, and more. The builder never
invents a new query: placing a widget means "render the output of that
existing endpoint inside my layout." When the layout is later rendered, each
tile fetches its own backing endpoint with the normal authenticated,
tenant-scoped request, so a dashboard can never widen the data access the
widget's source endpoint already enforces.

Because widgets reference the live endpoint catalog, a widget only exists in
the palette when its backing metric is live for your tenant — if a surface
you expected is missing, check that pillar's data is actually flowing.

## The widget palette

The palette groups widgets by category (Messaging, Deliverability, Voice,
CDP, Agents, Quality, Spend, Sustainability) and each entry shows its
visualization type — stat, line, bar, table, or gauge — so you know what
shape the tile will take before you add it. The current catalog:

| Widget                           | Category       | Answers                                                                                                  | Default tile | Visualization |
| -------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------- | ------------ | ------------- |
| Message volume                   | Messaging      | Sent / delivered / failed message counts over the window                                                 | 6×4          | Line          |
| Messaging spend                  | Messaging      | Aggregate messaging cost over the window                                                                 | 3×2          | Stat          |
| Messaging insights               | Messaging      | Per-carrier, per-country, and per-error-code delivery histograms                                         | 6×5          | Table         |
| Contact reasons                  | Messaging      | Why customers are contacting you — reason, category, and urgency rollup                                  | 6×4          | Bar           |
| Conversation sentiment           | Messaging      | Portfolio-level conversation sentiment trend                                                             | 6×4          | Line          |
| Deliverability                   | Deliverability | Per-channel deliverability rate and failure breakdown                                                    | 4×3          | Gauge         |
| Per-MNO delivery truth           | Deliverability | Silent-drop inference per mobile network operator, cross-checking delivery receipts against engagement   | 6×5          | Table         |
| Voice quality (MOS)              | Voice          | Aggregate mean opinion score, jitter, and packet loss for the window                                     | 3×2          | Stat          |
| Worst-quality calls              | Voice          | Lowest-MOS calls in the window, for drill-down                                                           | 6×5          | Table         |
| Queue live state                 | Voice          | Real-time waiting, handled, and agents-available for one queue                                           | 3×2          | Stat          |
| CDP data quality                 | CDP            | Contact profile health — missing email/phone, stale contacts, and an overall health score                | 4×3          | Gauge         |
| CDP event volume & cost forecast | CDP            | Projected CDP event volume and ingestion cost for the billing month                                      | 3×2          | Stat          |
| Agent state mix                  | Agents         | Distribution of agents across state and aux reason codes                                                 | 4×3          | Bar           |
| Agent QA scorecard               | Quality        | Per-agent quality scorecard — QA pass rate plus drift and regression alerts                              | 4×3          | Gauge         |
| LLM spend                        | Spend          | AI model usage rollup for the billing period                                                             | 3×2          | Stat          |
| Burn rate                        | Spend          | Average daily spend and projected days of runway remaining                                               | 3×2          | Stat          |
| Spend over time                  | Spend          | Daily spend series for the window                                                                        | 6×4          | Line          |
| Communications carbon (CO2e)     | Sustainability | Estimated per-channel CO2e of the messages and voice minutes you send, for ESG and procurement reporting | 6×4          | Bar           |

## Create a dashboard

1. Open **Insights → Dashboard Builder** in the console (visible to the
   owner, admin, developer, and viewer roles).
2. Set a **Dashboard name** and pick the **grid column count** — 6, 8, 12,
   16, or 24 columns. 12 is the default; use more columns when you want
   finer placement control.
3. From the **Widget palette** on the left, click a widget to drop it onto
   the canvas. A dashboard can hold up to 50 widgets.
4. For each placed widget use the editor card on the right to:
   * override the **title** (leave blank to keep the widget's own name),
   * adjust **width** (1 up to the column count) and **height** (1–24 row
     units) with the steppers,
   * reorder tiles with the up/down controls, or remove them.
5. When the layout reads right, click **Validate layout**. Validation is a
   dry-run against the API: it checks the layout shape, clamps coordinates,
   de-duplicates tile ids, and confirms every required parameter is set.
   On success the canvas adopts the normalized layout the server returned.

Your in-progress draft autosaves to this browser's local storage on every
edit, so closing or refreshing the page never loses work. The draft is
per-browser — it does not sync across devices or teammates. **Clear**
empties the canvas after a confirmation.

## Configure a widget

Configuration happens per tile, in the editor card on the right. Every
widget has a **size** (width and height in grid units, up to your column
count and 24 row units) and an optional **title override**. Beyond that,
each widget exposes the parameters its backing endpoint accepts:

* **`window`** — the look-back window for the metric, one of `24h`, `7d`,
  `30d`, or `90d`. Most widgets accept it.
* **`channel`** — an exact-match channel filter, one of sms, whatsapp, rcs,
  email, voice, or telegram. Accepted by the messaging, deliverability, and
  sentiment widgets.
* **Period or day-count parameters** — the spend family takes a billing
  month (`YYYY-MM`) or a day count; the burn-rate, spend-series, and carbon
  widgets take a window in days (default 30).
* **Required object parameters** — some widgets bind to a specific object:
  the Queue live state widget needs a queue id, and the Agent QA scorecard
  widget needs an agent id. Required parameters are marked with an asterisk
  in the widget editor; the canvas warns and the **Validate layout** button
  stays disabled until every required value is supplied.

Enum-constrained parameters (like `window` and `channel`) accept only their
listed values — validation rejects anything else.

### Validate, don't guess

Validation runs the same normalizer the API uses on a saved or shared
layout, so a layout that validates is one the embed renderer will render
unchanged. The builder also adopts normalized coordinates back onto the
canvas, so what you see after validation is exactly what a recipient of the
dashboard will see.

## Filters and drill-down

The builder itself is a composition surface, so its filter controls live on
the widget's parameters: the `window` and `channel` parameters above are
the per-tile filters you apply before sharing. For the wider, range-aware
filter experience — the explicit date range, channel and region filters,
and the row-level drill-down into carriers, countries, and error codes —
open the fixed **Analytics** surface (Insights → Analytics), which is the
canonical explorer the hub links to. The **Messaging insights** widget is
the drill-down you embed: it renders the same per-carrier, per-country,
and per-error-code histogram the Deliverability surface drills into, so a
shared dashboard can carry that breakdown without granting console access.

## Share and embed

Minting a share link is a governance action on the API (the link anyone
with the URL can open exposes tenant metrics), so **Share & embed** is
restricted to the **owner** and **admin** roles; the button only renders for
them, and the API rejects the request for other roles.

1. Fill in the dashboard name and every required widget parameter (the
   button stays disabled until those are set).
2. Click **Share & embed**.
3. Pick a lifetime — 1, 7, 30, 60, or 90 days (the default is 30, and the
   API clamps every request to 1–90 days) — optionally a title override,
   and **Generate link**.
4. Copy either:
   * the **Embed URL**, which opens a public, white-label page rendering
     the dashboard, or
   * the **Embed snippet**, a ready-made `<iframe>` pointing at that URL
     to drop into an intranet, portal, or backing-app page.

The signed link embeds the layout snapshot, your tenant scope, and the
expiry inline — there is no server-side save step, and the link keeps
working until it expires. Anyone with the link can view the dashboard until
then; to rotate access you generate a new link (the old one remains valid
until its expiry).

The embed page renders the **composition plus your white-label branding** —
the named metric tiles laid out on your grid, under your logo and colors —
not the live metric values. That page is intentionally view-only: the
signed token cannot call authenticated per-widget data endpoints. Use it
for "here is the dashboard layout with our branding", while operators who
need live numbers open the builder (or the matching Insights surface) in
the console.

An invalid, malformed, or expired token returns a friendly "invalid or
expired" page (the resolver answers 410/422), a burst of opens answers 429,
and any other fault surfaces as a service-unavailable notice — the recipient
never sees a raw error.

## Limits and failure modes

| Condition                                                          | Result                                                                                                                                           |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Dashboard has no widgets, no name, or a missing required parameter | **Validate layout** and **Share & embed** stay disabled; a warning banner explains the missing parameter                                         |
| Validation fails                                                   | The API returns a structured validation error naming the widget/parameter at fault; the builder shows it inline — fix the named field and re-run |
| More than 50 widgets placed                                        | Palette entries disable until you remove a tile                                                                                                  |
| Share token expired or malformed (410/422)                         | Embed page shows "invalid or expired" — generate a fresh link                                                                                    |
| A widget you placed is no longer in the catalog                    | On draft restore the stale tile is dropped silently (it would 404 anyway)                                                                        |

## Where exports live

The builder itself composes and shares layouts — it is not a data-export
surface. If you need a spreadsheet or an image of the *numbers*, use the
export affordance on the individual Insights metric page (for example the
Deliverability and Link-tracking surfaces ship CSV/workbook exports), or
pull the same endpoints the widgets call through the [Analytics
API](/api-reference/analytics) and export from your own tooling. A
dashboard link answers "show someone the composition," not "hand them a
file of the data."

## How this fits with the other Insights guides

* [Read the Insights dashboards](/guides/insights-dashboards) — what each
  fixed Insights surface answers and how to read it (cross-channel KPIs,
  retention curves, journey paths). This guide covers the complementary
  dashboard-*building* mechanics: the palette, layout, and share flow.
* [Insights API reference](/api-reference/insights) — the endpoint shapes
  behind the fixed surfaces (the widget catalog reuses the same read-only
  family).
* [Scheduled reports](/guides/scheduled-reports) — recurring email digests,
  when you need the numbers pushed to you rather than composed on a page.
