# Run reports
URL: /docs/cloud/telemetry

What the SDK reports about every assistant run, which fields each integration fills, and how to configure and enrich the reports.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

Every assistant response is a **run**. When a run finishes, the SDK sends one run report to the project: what happened, how long it took, which model and tools were involved, and how it ended. Reports never carry the user's messages, but they do carry the assistant's output text and the tool arguments and results, each cut at 50,000 characters, the error message, cut at 2,048, and whatever `metadata` the integration or your `beforeReport` hook attaches, so they can contain sensitive content; `beforeReport` can redact or drop a report and `telemetry: false` turns reporting off, see [Enriching or filtering reports](#enriching-or-filtering-reports). Reports are the source of the Runs, Models, Users and Overview pages in the dashboard.

Reporting is on by default for every integration that persists messages. This page describes the report, the fields each integration can fill, and the `telemetry` configuration on `AssistantCloud`.

## The run report

A report is one `POST /v1/runs` with the fields below. The SDK builds it with `createRunReport`, so every integration sends the same shape.

| Field                                                                      | Type                                     | Meaning                                                                                                                                                              |
| -------------------------------------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `thread_id`                                                                | string                                   | The cloud thread the run belongs to.                                                                                                                                 |
| `status`                                                                   | `"completed"`, `"incomplete"`, `"error"` | How the run ended. `incomplete` carries an `outcome_type`.                                                                                                           |
| `outcome_type`                                                             | see [Outcomes](#outcomes)                | Why an incomplete or failed run ended. Omitted for a completed run.                                                                                                  |
| `error`, `error_code`                                                      | string                                   | The failed run's message and code. The code is the error's `code` when it has one, else its class name (`AI_APICallError`).                                          |
| `message_id`                                                               | string                                   | The stored assistant message the run produced, so the dashboard can open it.                                                                                         |
| `duration_ms`                                                              | number                                   | Wall clock time from the first request to the last chunk.                                                                                                            |
| `first_token_ms`                                                           | number                                   | Time to the first streamed token.                                                                                                                                    |
| `steps`                                                                    | array                                    | One entry per model step: `input_tokens`, `output_tokens`, `reasoning_tokens`, `cached_input_tokens`, `tool_calls`, `start_ms`, `end_ms`, `finish_reason`.           |
| `total_steps`                                                              | number                                   | The number of steps.                                                                                                                                                 |
| `tool_calls`                                                               | array                                    | Every tool invocation with `tool_name`, `tool_call_id`, `tool_args`, `tool_result`, `tool_source` (`frontend` or `mcp`) and any nested `sampling_calls`.             |
| `input_tokens`, `output_tokens`, `reasoning_tokens`, `cached_input_tokens` | number                                   | Usage for the whole run.                                                                                                                                             |
| `model_id`, `provider`                                                     | string                                   | The model that served the run and the provider that served the model.                                                                                                |
| `output_text`                                                              | string                                   | The assistant output, truncated at 50,000 characters.                                                                                                                |
| `trace_id`                                                                 | string                                   | The W3C trace id of the server spans, when [trace correlation](/docs/cloud/traces) is set up. A report with a trace id merges into the run the server spans created. |
| `environment`, `release`, `tags`                                           | string, string, string\[]                | The deployment dimensions from the `telemetry` configuration. They become facets on the Runs page.                                                                   |
| `metadata`                                                                 | object                                   | Attributes attached through `beforeReport`, shown on the run's page.                                                                                                 |

Field limits: `error` is cut at 2,048 characters and `error_code` at 64, `output_text` at 50,000, `environment` at 64, `release` at 255, tags at 64 characters each and 20 per report, and `duration_ms` and `first_token_ms` are rounded to whole milliseconds. The endpoint is append only: a report may also carry `cost_usd` or `cost_details` to override the catalog price, and any key it does not know is kept in the run's attributes rather than rejected, so an older cloud accepts a newer SDK and the other way round.

## What each integration reports

The integrations observe runs differently, so they do not all fill every field.

| Field                                | assistant-ui runtime, `aui/v0`                                   | assistant-ui runtime, `ai-sdk/v6`                              | `useCloudChat`                         |
| ------------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------- |
| `status`, `error`, `error_code`      | yes                                                              | yes                                                            | yes                                    |
| `outcome_type`                       | `length`, `content_filter` and `aborted` from the message status | same, plus a `finishReason` the route puts in message metadata | all four, from the AI SDK finish event |
| `first_token_ms`, `duration_ms`      | yes                                                              | yes                                                            | yes                                    |
| `steps` with `start_ms` and `end_ms` | yes                                                              | yes                                                            | yes                                    |
| Per step `finish_reason`             | no                                                               | `"tool-calls"` on a step that called a tool                    | the finish event's reason              |
| `tool_calls` with `tool_source`      | without `tool_source`                                            | yes                                                            | yes                                    |
| Usage                                | from message metadata                                            | from message metadata                                          | from message metadata                  |
| `model_id`, `provider`               | from message metadata                                            | from message metadata                                          | from message metadata                  |
| `trace_id`                           | from message metadata                                            | from message metadata                                          | from message metadata                  |

The assistant-ui runtime rows apply to `useLocalRuntime` and `useChatRuntime`, whose history adapter persists and reports every run. The LangGraph, LangChain and Google ADK runtimes keep their own transcripts, so with them the cloud provides the thread list, titles and feedback but no run report; see [LangGraph](/docs/cloud/langgraph).

## Route configuration

Usage, model and provider only exist on the server, so the route has to put them into the message metadata the SDK reads. With the AI SDK, add a `messageMetadata` callback to the stream response:

```
import { convertToModelMessages, streamText } from "ai";
import { openai } from "@ai-sdk/openai";

export async function POST(req: Request) {
  const { messages } = await req.json();

  const model = openai("gpt-5.6-luna");
  const result = streamText({
    model,
    messages: await convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse({
    messageMetadata: ({ part }) => {
      if (part.type === "finish") {
        return { usage: part.totalUsage, finishReason: part.finishReason };
      }
      if (part.type === "finish-step") {
        return { modelId: part.response.modelId, provider: model.provider };
      }
      return undefined;
    },
  });
}
```

The SDK reads these metadata keys:

| Key             | Becomes                                                                                                                                                                                                                                                 |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `usage`         | The run's token counts. `inputTokens`, `outputTokens`, `reasoningTokens` and `cachedInputTokens` are read, and the AI SDK's older `promptTokens` and `completionTokens` names still work. Without `usage`, per step `steps[].usage` entries are summed. |
| `modelId`       | `model_id`. A per step `response.modelId` is read when the run level id is absent.                                                                                                                                                                      |
| `provider`      | `provider`. Server spans carry the provider as well when [trace correlation](/docs/cloud/traces) is on.                                                                                                                                                 |
| `finishReason`  | `outcome_type` for `length` and `content-filter`, and the `error` status for `error`.                                                                                                                                                                   |
| `traceId`       | `trace_id`. `withAssistantCloudTraceMetadata` sets it for you.                                                                                                                                                                                          |
| `samplingCalls` | Nested model calls made by tools, attached to the matching tool call. See [Traces](/docs/cloud/traces#sub-agent-model-tracking).                                                                                                                        |

Without this configuration the report still arrives, without model, provider and usage. The dashboard shows such runs under "No model reported" and cannot price them.

## Outcomes

The browser reports four outcomes. Runs the cloud executes itself, through [assistants](/docs/cloud/settings#llm-providers-and-assistants), add the server side ones.

| `outcome_type`   | `status`     | Meaning                                    | Reported by                                                       |
| ---------------- | ------------ | ------------------------------------------ | ----------------------------------------------------------------- |
| `aborted`        | `incomplete` | The user stopped the run.                  | the browser, and the assistant run endpoint on an aborted request |
| `disconnected`   | `incomplete` | The stream disconnected before completion. | `useCloudChat`                                                    |
| `length`         | `incomplete` | The model reached its output length limit. | the browser and server spans                                      |
| `content_filter` | `incomplete` | The provider filtered the response.        | the browser and server spans                                      |
| `timeout`        | `error`      | The run exceeded the assistant's timeout.  | the assistant run endpoint                                        |
| `rate_limited`   | `error`      | The provider answered 429.                 | the assistant run endpoint                                        |
| `provider_error` | `error`      | The provider answered another HTTP error.  | the assistant run endpoint                                        |
| `server_error`   | `error`      | The run failed inside the cloud.           | the assistant run endpoint                                        |

A failed run has `status: "error"` and, when the cause is known, an outcome from the second group. The Overview and the Runs page turn these into the completion rate and the outcome facets.

## Deployment dimensions

`environment`, `release` and `tags` on the `telemetry` configuration are stamped onto every report the client sends. They become facets on the Runs page, so a regression can be narrowed to one release or one environment.

```
const cloud = new AssistantCloud({
  baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
  anonymous: true,
  telemetry: {
    environment: "production",
    release: "2026.09.1",
    tags: ["web", "eu"],
  },
});
```

`release` is your application's version, not the SDK's. The SDK identifies itself separately: every request carries an `Aui-Sdk` header naming the `assistant-cloud` version and the integration packages on it, and Settings › Telemetry lists the versions a project has seen.

## Enriching or filtering reports

`beforeReport` runs last, with the assembled report. Return a modified report to add attributes, or `null` to drop it.

```
const cloud = new AssistantCloud({
  baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
  authToken: getToken,
  telemetry: {
    beforeReport: (report) => {
      if (report.thread_id === internalTestThread) return null;
      return { ...report, metadata: { ...report.metadata, plan: "pro" } };
    },
  },
});
```

`metadata` is stored as the run's attributes and shown on the run's page; keep it to a few short keys.

## Turning telemetry off

| Setting                        | Effect                                                                                                       |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `telemetry: false`             | No run reports and no [engagement events](/docs/cloud/engagement). Threads and messages are still persisted. |
| `telemetry: { events: false }` | Run reports stay on, engagement events stop.                                                                 |
| `telemetry: true` or omitted   | Everything on.                                                                                               |

## Where reports appear

- **Runs** lists every report with facets for status, outcome, model, provider, environment, release, tags and user, and an Analysis view over the same range.
- A run's page shows its steps, tool calls and usage as a timeline, and the server spans when a trace was correlated.
- **Models** aggregates runs and cost per model and provider, **Users** per end user, and the **Overview** carries the completion rate, latency percentiles and daily volume.

The [demo project](https://cloud.assistant-ui.com/demo) shows each of them on synthetic data.