Implementation:Langfuse Langfuse Traces UI Table Service
| Knowledge Sources | |
|---|---|
| Domains | Tracing, ClickHouse, UI |
| Last Updated | 2026-02-14 00:00 GMT |
Overview
This service provides functions for querying trace data from ClickHouse and converting it into UI-friendly table row formats for the Langfuse web application's traces table view.
Description
The traces-ui-table-service.ts module is the primary data access layer for the traces table displayed in the Langfuse web UI. It constructs complex ClickHouse SQL queries that join traces with observations and scores, applies dynamic filters, handles search, supports pagination, and returns data in multiple select modes: count, rows, metrics, and identifiers.
The core internal function getTracesTableGeneric uses TypeScript function overloads to provide type-safe return types based on the select parameter. It builds a Common Table Expression (CTE) query that aggregates observation statistics (token usage, cost, latency, error/warning counts) and score averages, then joins them with trace data. The service intelligently skips joins for observations or scores when they are not needed by the current query, improving performance for default views.
Key design decisions include:
- Using
FINALon ClickHouse tables only when non-default ordering is used, avoiding unnecessary deduplication overhead. - Propagating timestamp filters to observation and score subqueries for query optimization, since 98% of observations have start times within 5 minutes of trace timestamps.
- Supporting OTel projects that use immutable spans by skipping observation deduplication entirely.
- Using
LIMIT 1 BY id, project_idfor default ordering to handle deduplication without FINAL.
Four public convenience functions wrap the generic function: getTracesTableCount, getTracesTableMetrics, getTracesTable, and getTraceIdentifiers. Two converter functions (convertToUiTableRows and convertToUITableMetrics) transform raw ClickHouse row formats into UI-friendly types with proper BigInt, Decimal, and Date conversions.
Usage
Use this service when you need to:
- Fetch paginated trace data for the traces table UI with filtering, search, and ordering.
- Retrieve trace counts for pagination controls.
- Fetch trace metrics (latency, token usage, costs, scores, observation counts) for the metrics columns in the traces table.
- Get trace identifiers for bulk operations or exports.
Code Reference
Source Location
- Repository: Langfuse
- File: packages/shared/src/server/services/traces-ui-table-service.ts
- Lines: 1-605
Signature
// Types
export type TracesTableReturnType = Pick<TraceRecordReadType, "project_id" | "id" | "name" | "timestamp" | "bookmarked" | "release" | "version" | "user_id" | "session_id" | "environment" | "tags" | "public">;
export type TracesTableUiReturnType = Pick<TraceDomain, "id" | "projectId" | "timestamp" | "tags" | "bookmarked" | "name" | "release" | "version" | "userId" | "environment" | "sessionId" | "public">;
export type TracesMetricsUiReturnType = {
id: string;
projectId: string;
promptTokens: bigint;
completionTokens: bigint;
totalTokens: bigint;
latency: number | null;
level: ObservationLevelType;
observationCount: bigint;
calculatedTotalCost: Decimal | null;
calculatedInputCost: Decimal | null;
calculatedOutputCost: Decimal | null;
scores: ScoreAggregate;
usageDetails: Record<string, number>;
costDetails: Record<string, number>;
errorCount: bigint;
warningCount: bigint;
defaultCount: bigint;
debugCount: bigint;
};
export type FetchTracesTableProps = {
select: "count" | "rows" | "metrics" | "identifiers";
projectId: string;
filter: FilterState;
searchQuery?: string;
searchType?: TracingSearchType[];
orderBy?: OrderByState;
limit?: number;
page?: number;
clickhouseConfigs?: ClickHouseClientConfigOptions | undefined;
tags?: Record<string, string>;
};
// Converter functions
export const convertToUiTableRows: (row: TracesTableReturnType) => TracesTableUiReturnType;
export const convertToUITableMetrics: (row: TracesTableMetricsClickhouseReturnType) => Omit<TracesMetricsUiReturnType, "scores">;
// Public query functions
export const getTracesTableCount: (props: { projectId: string; filter: FilterState; searchQuery?: string; searchType: TracingSearchType[]; orderBy?: OrderByState; limit?: number; page?: number; }) => Promise<number>;
export const getTracesTableMetrics: (props: { projectId: string; filter: FilterState; searchQuery?: string; orderBy?: OrderByState; limit?: number; page?: number; clickhouseConfigs?: ClickHouseClientConfigOptions; }) => Promise<Array<Omit<TracesMetricsUiReturnType, "scores">>>;
export const getTracesTable: (p: { projectId: string; filter: FilterState; searchQuery?: string; searchType?: TracingSearchType[]; orderBy?: OrderByState; limit?: number; page?: number; clickhouseConfigs?: ClickHouseClientConfigOptions; }) => Promise<TracesTableUiReturnType[]>;
export const getTraceIdentifiers: (props: { projectId: string; filter: FilterState; searchQuery?: string; searchType?: TracingSearchType[]; orderBy?: OrderByState; limit?: number; page?: number; clickhouseConfigs?: ClickHouseClientConfigOptions; }) => Promise<Array<{ id: string; projectId: string; timestamp: Date }>>;
Import
import {
getTracesTableCount,
getTracesTableMetrics,
getTracesTable,
getTraceIdentifiers,
convertToUiTableRows,
convertToUITableMetrics,
} from "@langfuse/shared/src/server/services/traces-ui-table-service";
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| projectId | string | Yes | The project ID to filter traces for |
| filter | FilterState | Yes | Array of filter conditions (e.g. timestamp ranges, trace names, user IDs, score filters) |
| select | "rows" | "metrics" | "identifiers" | Yes | Determines the shape of the returned data |
| searchQuery | string | No | Free-text search query to match against traces |
| searchType | TracingSearchType[] | No | Types of search to perform (e.g. trace name, user ID) |
| orderBy | OrderByState | No | Column and direction for ordering results |
| limit | number | No | Maximum number of results to return (for pagination) |
| page | number | No | Page number for pagination (0-indexed) |
| clickhouseConfigs | ClickHouseClientConfigOptions | No | Optional ClickHouse client configuration overrides |
| tags | Record<string, string> | No | Tags to attach to the ClickHouse query for tracing/logging |
Outputs
| Name | Type | Description |
|---|---|---|
| count result | number | Total number of matching traces (when select="count") |
| rows result | TracesTableUiReturnType[] | Array of trace row data with UI-friendly field names and types (when select="rows") |
| metrics result | Omit<TracesMetricsUiReturnType, "scores">[] | Array of trace metrics including latency, token usage, costs, and observation counts (when select="metrics") |
| identifiers result | { id: string; projectId: string; timestamp: Date }[] | Array of trace identifiers (when select="identifiers") |
Usage Examples
// Get paginated trace rows for the UI table
const traceRows = await getTracesTable({
projectId: "my-project-id",
filter: [],
searchQuery: "user query",
searchType: ["trace-name"],
orderBy: { column: "timestamp", order: "DESC" },
limit: 50,
page: 0,
});
// Get total count for pagination
const totalCount = await getTracesTableCount({
projectId: "my-project-id",
filter: [],
searchType: [],
});
// Get metrics (latency, costs, token usage) for trace rows
const metrics = await getTracesTableMetrics({
projectId: "my-project-id",
filter: [],
limit: 50,
page: 0,
});
// Get trace identifiers for bulk operations
const identifiers = await getTraceIdentifiers({
projectId: "my-project-id",
filter: [],
limit: 1000,
page: 0,
});