Documentslangfuse/langfuse
Filter State Management
Filter State Management
Type
Topic
Status
Published
Created
Jul 9, 2026
Updated
Jul 9, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Filter State Management#

Filter state in Langfuse table components is split across three cooperating layers: a sidebar filter system (explicit user filters + implicit defaults), a date/time range system (with cross-view persistence), and an external override pattern used by embedded preview tables.


Architecture Overview#

externalFilterState (prop, optional)
      │ wins when present
useSidebarFilterState ──► effectiveFilterState ──┐
     │ (+ implicit defaults) │
     ▼ ├──► filterState ──► API query
explicitFilterState ───────────────────────────── ┘ (+ dateRangeFilter, userIdFilter, etc.)
     └── useQueryFilterState (URL params + session storage)

useTableDateRange / useGlobalDateRange ──► dateRange (externalDateRange wins if set)

Every major table — TracesTable, ObservationsTable, EventsTable — follows the same pattern.


External Filter State Override#

Tables accept externalFilterState?: FilterState and externalDateRange?: TableDateRange props for embedding scenarios (e.g., showing a scoped trace list inside a user detail page).

When either is present, it completely replaces the internally-built filter state:

// TracesTable (line 347)
const filterState = externalFilterState || combinedFilterState;

// EventsTable (line 421)
const filterState = externalFilterState || combinedFilterState;

For the date range the same pattern applies — externalDateRange is preferred over the table's own useTableDateRange result:

const dateRange = externalDateRange ?? tableDateRange;

When hideControls=true (the embedded-preview flag), URL persistence is also disabled via disableUrlPersistence: hideControls in the useSidebarFilterState call .


Internal Filter State (useSidebarFilterState)#

useSidebarFilterState manages the sidebar filter UI and returns three states:

PropertyMeaning
explicitFilterStateFilters the user explicitly set (persisted to URL/session storage)
effectiveFilterStateExplicit filters + implicit defaults (e.g. environment defaults, hidden environments); used for API queries

Implicit environment defaults are injected via implicitDefaultConfig: DEFAULT_SIDEBAR_IMPLICIT_ENVIRONMENT_CONFIG and are excluded from URL serialization to keep shared links clean .

The toolbar displays explicitFilterState (user-visible chip count), while API queries use effectiveFilterState (includes implicit defaults) .

Query/URL Filter State (useQueryFilterState)#

useQueryFilterState is a lower-level hook that encodes/decodes FilterState to URL query parameters and session storage using a pipe-delimited format. Tables use it to seed a type-specific default filter (e.g. the generation type filter) that is bypassed when a saved view is loaded .


Date Range Persistence#

useTableDateRange returns a timeRange and setTimeRange used by every table. The time range is converted to an absolute TableDateRange ({ from, to }) via toAbsoluteTimeRange and then assembled into startTime date filter conditions before being merged into combinedFilterState .

Cross-view persistence (June 2026+)#

PR #14535 introduced useGlobalDateRange and the resolveTimeRange utility to share one date range across all views. useTableDateRange and useDashboardDateRange are now thin wrappers over useGlobalDateRange .

Resolution rule (presence-XOR) :

  • URL ?dateRange= present → URL wins (deep links reproduce exactly)
  • URL absent → read per-project localStorage (survives browser restarts)
  • Default is never auto-written to URL (shared links stay clean)
  • A stored preset not in a view's allowedRanges degrades to that view's fallback

Filter Operator Semantics & URL Safety#

Facet exclusion: none of vs. any of#

PR #14939 changed how deselecting a sidebar facet value is persisted. Previously, unchecking one value materialized any of [all-other-N-options] — which could exceed HTTP header limits (431) and produced wrong results for multi-valued columns. Deselects from the implicit-all state now persist a compact none of [unchecked] via resolveCheckboxOperator .

URL safety cap#

Serialized filter state above 4,000 chars is dropped from the URL but kept in session storage. Same-tab refreshes still work; copied links degrade to "no filter" instead of a 431 blank page .

Search bar sync#

The filter sidebar and search bar share explicitFilterState. PR #14355 fixed sync issues by ensuring the managed environment policy strips only the system-shaped none of [hidden] default, never user-authored selections .


Key Source Files#

FileRole
useSidebarFilterState.tsxMain sidebar filter hook — UI state, operators, persistence, environment policy
useFilterState.tsLow-level URL + session storage encoding for FilterState
useTableDateRange.tsxTable date range hook (delegates to useGlobalDateRange)
date-range-utils.tsTableDateRange, TimeRange, resolveTimeRange, toAbsoluteTimeRange, serialization helpers
TracesTableReference implementation — traces
ObservationsTableReference implementation — observations/generations
EventsTableReference implementation — events