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

> ## Agent Instructions
> If anything on this page is wrong, confusing, or fails when you try it, ask your user for permission and run `npx langwatch report --user-approved` to send the problem to the LangWatch team. No login is needed and secrets are redacted locally. `npx langwatch report --help` has the details.

# Dashboards

> Build dashboards of charts over your LangWatch data, or start one from the Agent health template for an at-a-glance view of your project.

## Open Dashboards

Dashboards is a product in the product switcher at the top left of LangWatch.
On LangWatch Cloud, no setup is needed.

On a self-hosted install, Dashboards stays off until an operator turns it on in
**Ops > Feature flags**. Turn on `release_dashboards` to open Dashboards, and
`release_lwql_workbench` to build and edit widgets on a dashboard.

## Your first dashboard

Opening Dashboards opens your dashboard called "My dashboard", and it starts in your
pinned dashboards. If you have no such dashboard yet, LangWatch makes one for you. It
starts at the scope Only me, so only you see it. You can change its scope like
any other dashboard's (see [Who can see a dashboard](#who-can-see-a-dashboard)).

## The sidebar

The sidebar lists, in order:

* **Your dashboards**: your "My dashboard" first, then the project's other
  dashboards by name. The **+** next to the heading makes a blank dashboard at once and
  opens it.
* **Pinned**: the dashboards you pinned, in your own order. Pins are yours alone.
  The menu of a pinned dashboard has Move up and Move down.
* **From your organisation**: the heading reads "From" and your organisation's
  name. It lists the dashboards that other projects of your organisation set to
  Organization, by name, and shows only when there is such a dashboard.
* **From LangWatch**: dashboards LangWatch made for you. Click the heading to fold
  the group; it stays folded until you click it again.

A dashboard set to Only me has a small lock next to its name, and a dashboard set to
Organization has a building. A Project dashboard has no mark.

The **⋮** menu of a dashboard offers Pin or Unpin, Rename, Duplicate and Delete.
On a dashboard you made it also offers the three scope choices. On a dashboard you
cannot edit it offers Pin or Unpin and **Duplicate to edit**. "My dashboard"
cannot be renamed or deleted.

## Start from a template

A dashboard without widgets shows the ask bar, suggested questions, and "Or start
from a template" with the three From LangWatch dashboards and a **View all
templates** link. The templates library lists every ready template by Grow,
Protect, Profit and Trust, with a search box and filters for the category and
the agent type.

**Add to this project** on a card creates a new dashboard named after the template
(numbered "Agent health 2" and so on if the name is taken), at the scope Project,
with the template's widgets. A template you already added shows **Added**,
linking to its dashboard.

When Langy is enabled for your project, Langy opens with the template's report
prompt ready in the composer, unsent. The prompt also asks Langy to check what
the dashboard needs that your project has not set up yet, and names the widgets
that wait for that data. Without Langy the dashboard is made and no
prompt is drafted.

A widget whose data is not set up yet says what is missing and links to the
page that sets it up, such as evaluations, scenarios or feedback.

The Agent health template holds five widgets:

* This period
* Status today
* Needs attention
* Top request my agent cannot serve
* Conversations resolved per day

A new dashboard is yours like any other: every widget on it can be edited,
duplicated, moved, resized or deleted, and your changes do not affect the
template.

## From LangWatch dashboards

The From LangWatch group in the sidebar holds Release check, "Can I trust my
numbers?" and Where my agent breaks. Each is a template shown live over your
data and read-only: you cannot move, edit or add anything on it, and LangWatch
stores no copy.

To change one, open its **⋮** menu in the sidebar and pick **Duplicate to
edit**. That makes your own dashboard, named after the template plus "(copy)", with the template's
widgets and opens it. The dashboard's header has no such button.

## Period and grain

Every dashboard has a period, from Live (the last hour) up to one year, defaulting
to 30 days, and a grain: auto, minute, hour, day or week. A grain is offered only
when it fits the period, and a grain that does not fit is greyed out. Every widget
on the dashboard reads over that period and grain.

## Keep the data fresh

The header has one period control. Its menu has three columns, Range, Grain and
Refresh, and ends with **Refresh now**, which reloads every widget on the dashboard.
The Refresh column reloads every widget every minute, every 5 minutes, or never
(Off).

Pick **Live** for the last hour, rolling and refreshed every minute. The other
refresh choices are greyed out until you pick another range.

## Building your own dashboard

On a dashboard, you can rename it from the sidebar menu and add a description.
**Add a widget** opens the picker; **I'll build it myself** there opens the
widget editor, where you write the widget's code and its LangWatchQL queries.
Move a widget by its drag handle and resize it from its corner. Each widget's
menu offers:

* **Edit with Langy**: asks Langy to change the widget. Only when Langy is available.
* **Edit code**: opens the widget editor on that widget's code and queries.
* **Copy widget id** and **Copy API snippet**: copy what the REST API needs to
  edit the widget.
* **Set an alert** and **Send as a report**: draft Langy to alert on, or
  schedule, that widget. Only when Langy is available.
* **Duplicate**: adds a copy of the widget.
* **Delete**: removes the widget.

### What a widget's queries count

Every query in a widget has a built-in **sources** parameter: the trace origins
it counts. The widget editor shows it as the first row under **Parameters** on
the **Queries** tab, one pill per source. Remove a pill to stop counting that
origin, or pick one from **Add source**:

* `application`: your own agent. A trace with no origin set counts here.
* `simulation`, `evaluation`, `sample`, `coding_agent`, `ai_tool`, `gateway`,
  `workflow`, `playground`: traces LangWatch itself produces.
* `langy`: your conversations with Langy.
* `other`: any origin not listed above.

A new widget counts `application`, and a stock widget from the template
does too. A widget about Langy's failed requests adds `langy`. The preview runs
again when you change the sources, and each card names its sources in a quiet
line underneath. A query with no source picked returns no rows, and its widget
says **No sources picked**.

Sources only apply where the SQL reads the parameter. A query that does not read
`{dashboard_context_sources:Array(String)}` counts every origin, and its card
says **Sources: all sources**. A widget saved before this release keeps its SQL,
so it counts every origin until you edit it to read the parameter or add it
again from the template.

## Who can see a dashboard

Every dashboard has a scope, shown next to its title:

* **Only me**: only you see the dashboard.
* **Project**: everyone in the project sees it. A new dashboard starts here.
* **Organization**: everyone in your organisation sees it, in each of their
  projects. In each project the dashboard shows that project's own data, and each
  member sees what their role lets them see.

Only the member who made a dashboard can change its scope, from the control next
to the title or from the dashboard's **⋮** menu in the sidebar. A project admin
cannot. Everyone else sees the scope as a badge. Who can edit or delete a dashboard
does not change: that still follows your role's analytics permissions.

LangWatch asks you to confirm a change only when somebody loses the dashboard: when
you set a dashboard to Only me that other members pinned, and when you lower a
dashboard from Organization. Every other change happens at once, and the note that
follows has an **Undo**. Other members' pins are kept, and come back if you
widen the scope again.

The project where a dashboard was made owns it. An Organization dashboard can be edited
only in that project. In every other project it is read-only: you cannot add,
move, edit or delete a widget, and the header says which project owns the dashboard.
To change it, pick **Duplicate to edit** in the dashboard's **⋮** menu in the
sidebar. That makes your own copy in the project you are in.

An Organization dashboard also has a **Project** control in its header. It names the
project whose data you see, and lists the projects of your organisation that you
can open. Pick one to open the same dashboard under that project.

If you open the address of a dashboard that you may not see, the page says "This
dashboard is not available". The dashboard was deleted, or the member who made it
set its scope to Only me.

A project API key reads the project's dashboards except the ones set to Only me.

Alerts and scheduled reports do not read a dashboard set to Only me either. An alert
or a report on a chart of such a dashboard sends no chart until you widen the
dashboard's scope.

## Asking questions

Every dashboard has an ask bar under its header, reading "What do you want to
know?". On a stored dashboard, clicking it opens **Add a widget** with the cursor in
its search. On a From LangWatch dashboard, the bar opens Langy when Langy is
available, with the dashboard as context and no question sent yet.

The picker lists suggested questions, grouped by the question tree, with a
search and filters for the category and the agent type. Picking one adds that
question's widget to the dashboard, below the widgets already there. When Langy is
enabled for your project, Langy then opens with the question's prompt ready in
the composer, with the dashboard as context, so you can read it and send it with one
click.

Without Langy the picker still lists every question, and picking one adds its
widget. The pinned **Ask Langy** footer, and the **Ask** button next to the
search field, send your own question to Langy directly.

On a dashboard that already has widgets, the **Add a widget** box below the widgets
and the **Add a widget** button in the header both open the picker. Every widget
has an **Ask Langy** button when Langy is available; it drafts a prompt with the
widget's name, its queries and the period.

## How the data is read

All dashboard data is read with LangWatchQL, LangWatch's query layer over your
traces, evaluations and cost data.

A widget query has two settings beside its SQL. `sources` lists the trace sources `{dashboard_context_sources:Array(String)}` is bound to (`application` by default), and a query is kept to them only where its SQL uses that parameter in a condition, such as `WHERE Source IN {dashboard_context_sources:Array(String)}`. A query that does not use it is not filtered by `sources` and counts every source, and its card says "all sources".

`projects` lists the projects the query reads, bound to `{dashboard_context_projects:Array(String)}`; a query that names none reads its board's project.

A project you cannot read makes that card draw "You can't read a project this widget uses" without naming it. When the server cut a run's rows, such as a project shared only from a date, the card shows one (i) line saying so.

Rolling back to a release before this one shows multi-project widgets for the board's
project only. A rollback is not supported for this feature.

## Build dashboards from your own AI agent

Your coding assistant can build and edit LangWatch dashboards for you, through
the [LangWatch MCP server](https://langwatch.ai/docs/integration/mcp.md).

### Connect the MCP server

Connect Claude Code, Cursor, or another MCP-capable assistant to LangWatch
first. Follow the [LangWatch MCP Server setup guide](https://langwatch.ai/docs/integration/mcp.md) to add
the server and set your API key.

### Dashboard tools

Once connected, your agent has these dashboard tools:

* `list_dashboards`: list the project's dashboards, with the id each
  widget tool takes.
* `get_dashboard`: read one dashboard by its id.
* `create_dashboard`: create an empty dashboard.
* `rename_dashboard`: change a dashboard's name.
* `delete_dashboard`: delete a dashboard and its widgets.
* `list_dashboard_widgets`: list the widgets of one dashboard. Pass the
  `dashboardId`.
* `run_query`: run one read-only LangWatchQL (LWQL) statement and see the rows
  it returns. Use this to check a query before it goes into a widget.
* `add_dashboard_widget`: create a custom widget and add it to a dashboard.
* `update_dashboard_widget`: change a widget's name, code, queries or
  description. Pass the dashboard id, the widget id, and only the fields to
  change. Every field you leave out keeps its value.
* `delete_dashboard_widget`: remove a widget from a dashboard.

The old Analytics Reports have their own tools: `platform_list_analytics_reports`,
`platform_get_analytics_report`, `platform_create_analytics_report`,
`platform_rename_analytics_report` and `platform_delete_analytics_report`. The
tools that act on an existing report (`platform_get_analytics_report`,
`platform_rename_analytics_report` and `platform_delete_analytics_report`) take
a `reportId`. Analytics Reports hold charts, not widgets.

### The widget definition format

A widget has two parts:

* **`code`**: a TSX source file. It runs sandboxed in the browser and renders
  the widget's chart or panel.
* **`queries`**: up to 8 named LangWatchQL statements the code can read from.
  Pass them as `{ "<name>": "<LWQL SQL>" }`, or as a list of `{ name, sql }`
  entries.

Ask your agent to validate each query with `run_query` before it calls
`add_dashboard_widget`. A query only actually runs once the widget renders
inside the sandbox, so catching a mistake in the SQL earlier, with
`run_query`, is faster than catching it on the dashboard.

### The LW widget API

Inside `code`, a global `LW` object gives the widget everything it needs:

* `LW.dashboardContext`: the dashboard's current time window, granularity,
  timezone and theme.
* `LW.params`: the widget's own author-declared parameter values.
* `LW.theme`: the dashboard's current colour theme (`"light"` or `"dark"`).
* `LW.query(name, params?)`: runs one of the widget's named queries and
  returns its rows.
* `LW.useChartQuery(name, params?)`: the React hook version of `LW.query`.
  Gives `data`, `completeness`, `isLoading`, `isFetching`, `isError`, `error`,
  `status`, and `refetch`, and refetches automatically when the dashboard's
  time window or granularity changes. Use this instead of `LW.query` in most
  widgets.
* `LW.setHeight(px)`: resizes the widget's frame once its content's height is
  known.
* `LW.onDashboardContextChange(callback)` / `LW.useDashboardContext()`:
  subscribe to, or read, the dashboard's live context.
* `LW.useParams()`: read the widget's author-declared parameter values.
* `LW.error(err)`: report an error without throwing.
* `LW.navigate(target, params?)`: navigate the host to an allowlisted target,
  such as a trace list or a single trace.

### Missing data: the `completeness` report

A query that follows the dashboard's time window also returns a
`completeness` report next to its rows. `POST /api/v1/query` returns it too
when you pass a `timeWindow`. Use it so a widget never shows missing data as
zero.

```ts theme={null}
completeness: {
  state: "complete" | "partial" | "missing" | "no_traffic";
  unit: string;   // what `total` counts: "traces", "spans", "evaluations"
  total: number;  // rows of that view in the window
  fields: { field: string; label: string; present: number }[];
  buckets?: { start: string; n: number }[];        // ISO start, UTC
  unpriced?: { count: number; models: string[] };
}
```

* `state`: `no_traffic` means no rows arrived in the period. `missing` means a
  field the query reads is on no row: show a setup step that names the field
  to send. `partial` means some rows lack a field, or some cost has no price.
* `fields`: one entry per field the query reads that can be empty, with how
  many of `total` rows carry it.
* `buckets`: only when the query follows the dashboard granularity. It lists
  every bucket in the window, including empty ones at the start and the end,
  with `n: 0`. Draw an empty bucket as a gap for a rate, an average or a
  percentile, never as 0. A count may be 0.
* `unpriced`: only when the query reads cost. `count` is the rows with at
  least one span whose model has no price, and `models` names those models. A
  cost total with unpriced rows is a lower bound: show it as "\$830+".
  Traces recorded before LangWatch started tracking this report no unpriced
  spans, so on older periods the absence of `unpriced` rows is not proof that
  every span was priced.

The report is absent when the query does not follow the dashboard's time
window, when it reads a per-minute rollup view, or when it could not be built.
Treat an absent report as "unknown", not as "complete".

### Example prompt

```text theme={null}
Add a widget to my Agent health dashboard that shows p95 latency by model
for the last 7 days.
```

Your agent will validate the LWQL with `run_query`, write the widget's TSX
code against `LW.useChartQuery`, and call `add_dashboard_widget` to add it to
the dashboard.

### Edit a widget through the REST API

The same edit works without MCP. Send a `PATCH` with your project API key and
only the fields to change:

```bash theme={null}
curl -X PATCH "https://app.langwatch.ai/api/v1/projects/$PROJECT_ID/analytics/dashboard-widgets/$WIDGET_ID" \
  -H "X-Auth-Token: $LANGWATCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Errors per day", "code": "<the widget code>"}'
```

The body takes any of `name`, `code`, `queries` and `description`. Each query
may carry `sources`, such as `["application", "langy"]`; a query sent without
it keeps the sources stored under its name, and `"sources": null` returns it to
`application`. A query renamed without `sources` has no stored list under its new
name, so it counts `application`; send its `sources` with the rename to keep them.

The answer is the updated widget. Each widget also records where it came from in
`definition.source`: a catalogue template, Langy, the code editor or the API.
A widget you create through the API without a `source` is recorded as `api`.

## Manage dashboards from code

The SDKs, the CLI and the REST API manage the same dashboards and widgets as
the app.

```typescript TypeScript theme={null}
import { LangWatch } from "langwatch";

const client = new LangWatch();

const dashboards = await client.dashboards.list();
const dashboard = await client.dashboards.create({ name: "Agent health" });

await client.dashboards.update({
  dashboardId: dashboard.id,
  name: "Agent health (prod)",
});

const widgets = await client.dashboards.listWidgets(dashboard.id);
```

```python Python theme={null}
import langwatch

dashboards = langwatch.dashboards.list()
dashboard = langwatch.dashboards.create(name="Agent health")

langwatch.dashboards.update(dashboard_id=dashboard.id, name="Agent health (prod)")

widgets = langwatch.dashboards.list_widgets(dashboard_id=dashboard.id)
```

```bash CLI theme={null}
langwatch dashboard list
langwatch dashboard create "Agent health"
langwatch dashboard update <dashboardId> --name "Agent health (prod)"
langwatch dashboard widget list <dashboardId>
langwatch dashboard delete <dashboardId>
```

```bash REST theme={null}
curl "https://app.langwatch.ai/api/v1/dashboards" \
  -H "X-Auth-Token: $LANGWATCH_API_KEY"
```

A widget has its verbs under `widget`: `langwatch dashboard widget
list|get|add|update|delete <dashboardId> [<widgetId>]`, and
`createWidget`, `getWidget`, `updateWidget` and `deleteWidget` in the
TypeScript SDK (`create_widget`, `get_widget`, `update_widget` and
`delete_widget` in Python).

### The REST API

`/api/v1/dashboards` serves dashboards and their widgets from API version
`2026-10-26`. A request pinned to an earlier `X-API-Version` gets a 404. See
[API reference > Dashboards](https://langwatch.ai/docs/api-reference/dashboards/overview.md).

Analytics Reports dashboards are at `/api/v1/analytics/reports`.

### Analytics Reports

The old Analytics Reports are a separate API: `client.analyticsReports` and
`langwatch.analytics_reports` in the SDKs, `langwatch analytics-report
list|get|create|update|delete` in the CLI, and `/api/v1/analytics/reports` over
REST.

### Names that changed

`langwatch dashboard` now manages the new Dashboards (widgets under
`langwatch dashboard widget`); it used to manage the old Analytics Reports,
which are now `langwatch analytics-report`. The `dashboards` and
`dashboard-widget` CLI groups, `client.boards`, `langwatch.boards`,
`BoardsFacade` and `DashboardWidgetsApiService` are removed, with no alias:
use `client.dashboards` and `langwatch.dashboards`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.