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

# Cross-trace cost dashboard SQL patterns

> Build accurate cross-trace cost dashboards by filtering on root-span metadata and aggregating costs across multiple projects using SQL patterns.

> [!NOTE]
>
> **Applies to:**
>
> * Plan - Pro and Enterprise for custom SQL charts
> * Deployment - Any
> *
> * Use case - How to build accurate multi-project cost dashboards and SQL charts that filter by root-span metadata (user\_id) while aggregating estimated\_cost() across traces/projects

## Summary

Use Cross-trace filtering for cost charts filtered by root-span metadata so contributing child spans remain included.

## What is happening

Span filtering matches individual spans. A filter on a field that exists on a different span will exclude those measured spans. Cross-trace filtering includes all spans from traces where any span matches the filter.

## Fix or suggestion

For unattributed cost across projects, use a per-trace aggregation pattern. Group by `root_span_id`, surface metadata with `any_value()`, sum `estimated_cost()` for the selected spans, then filter for missing `user_id` and aggregate in an outer query.

Example per-trace rollup across projects:

```sql theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
SELECT coalesce(sum(trace_cost), 0) AS unattributed_cost
FROM (
  SELECT
    root_span_id,
    any_value(metadata.user_id) AS user_id,
    sum(CASE WHEN metadata.braintrust.integration_name = 'langchain-py' THEN estimated_cost() ELSE 0 END) AS trace_cost
  FROM project_logs('proj-id-1', 'proj-id-2', 'proj-id-3')
  GROUP BY root_span_id
) AS per_trace
WHERE user_id IS NULL
```

### Option 1: Use `spans` shape and `WHERE is_root` for root-only inspection

Use this when you only need root-span rows. `WHERE is_root = true` is also valid.

Example: count root spans and roots with `user_id` for one project.

```sql theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
SELECT
  metadata.braintrust.integration_name AS integration,
  count(*) AS root_spans,
  count(metadata.user_id) AS root_spans_with_user_id
FROM project_logs('99fa755f-3519-4f5b-9e36-e1dd23917dca')
WHERE is_root
GROUP BY integration
```

### Option 2: Use `traces` or `summary` shape with `ANY_SPAN(...)`

Use this when you need the `traces` or `summary` shape but must restrict traces by a root-span condition.

Example: match traces whose root span has a `metadata.user_id` value of `123`.

```sql theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
SELECT *
FROM project_logs('proj-id', shape => 'traces')
WHERE ANY_SPAN(is_root AND metadata.user_id = '123')
```

## How to confirm it worked

* Use the root-count query to inspect where `user_id` is present. Roots without `user_id` will still have zero `root_spans_with_user_id`.
* Compare summed `estimated_cost()` before and after switching to Cross-trace filtering. Totals can change because additional spans contribute. Each span's estimated cost calculation remains unchanged.

## Notes

* Select projects by passing their IDs to `project_logs()` because `project_id` is not guaranteed as a row field.
* For a per-project breakdown, query each project separately. Passing multiple project IDs combines their data.


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