FaqWorking with the observations table

Working with the observations table

In Langfuse v4, every operation your application performs (LLM calls, tool executions, retrievals, agent steps) is one row in a single observations table. A trace is just the set of rows sharing a trace_id; the data model docs explain the model.

That means more rows than the old traces table, which is expected. Work with filters and saved views, not by scrolling: filter by observation name, type, or model, then save the view. The filter sidebar shows available values with counts. Filters depend on trace-level attributes (user_id, session_id, tags) living on every observation; the SDKs propagate them via propagate_attributes() / propagateAttributes() (see adding attributes).

Common views

Save 2-3 of these as saved views for one-click access:

I want to see…How to filter
Key operationsFilter by observation name or type matching your most important operations
All LLM generationsFilter type = generation
Expensive LLM callsFilter type = generation, sort by total_cost descending
Errors for a specific userFilter by user_id and level = ERROR
Operations scoped to a sessionFilter by session_id, sort by latency descending
All operations for one traceFilter by trace_id
Application entry pointsFilter Is Root Observation = true
Model latency comparisonFilter type = generation, group by model in a dashboard or sort by model column
Cost, latency, or errors by dimensionSelf-serve dashboards

Start with root observations

For projects that ingest with Python SDK ≥ 4.7.0 or JS/TS SDK ≥ 5.4.0, Langfuse applies Is Root Observation = true when you open the observations table without a saved view, shared filter link, or other table state. You see your application entry points first and drill into their child operations from there.

The filter includes two kinds of roots:

  • Outer roots are top-level observations with no parent.
  • App roots are the highest exported application observations. When an OpenTelemetry or infrastructure span is the outer parent and the SDK filters it from export, the exported child still carries its parent span ID, so a "no parent" filter alone would miss it. App-root-aware SDKs mark that entry point instead.

Remove the filter in the sidebar to see every operation; Langfuse remembers that choice. Saved views and links with table state keep their own filters, and if the filter matches no roots while other observations exist, Langfuse removes it automatically.

Data appearing with up to a 10-minute delay? You are ingesting via older SDKs or via OpenTelemetry without the x-langfuse-ingestion-version: 4 header. Upgrade to Python SDK ≥ 4.7.0 / JS/TS SDK ≥ 5.4.0, or set the header on your exporter; see Versions & Compatibility.


Was this page helpful?

Last edited