DocsDeprecated API migration

Migration of deprecated APIs

This page maps every deprecated Langfuse REST endpoint to its replacement, with parameter mappings, semantic differences, and before/after examples. Many of these changes follow from the observations-first data model: traces and observations are no longer separate entities, and reads are consolidated onto fewer, faster endpoints.

If you access the API through the Langfuse SDKs, use the SDK upgrade guides instead: Python v3 to v4 and JS/TS v4 to v5. This page covers direct REST usage only.

Still need the deprecated endpoints? They are documented in the Deprecated APIs reference.

This page is also served as plain markdown at https://langfuse.com/docs/deprecated-api-migration.md for programmatic use, e.g. by coding agents. The section anchors below are stable.

Quick reference

Deprecated endpointReplacementDetails
GET /observations, GET /observations/{id}GET /v2/observationsObservations
GET /traces, GET /traces/{id}GET /v2/observations, filtered by traceIdTraces
GET /sessions, GET /sessions/{id}GET /v2/observations, filtered by sessionIdSessions
GET /metrics, GET /metrics/dailyGET /v2/metricsMetrics
GET /scores, GET /scores/{id}, GET /v2/scores, GET /v2/scores/{id}GET /v3/scoresScores
GET /datasets/{name}/runs, GET /datasets/{name}/runs/{runName}GET /experiments, GET /experiment-itemsDataset runs
POST /ingestion, POST /traces, POST /spans, POST /generations, POST /eventsPOST /otel/v1/traces (OTLP/HTTP)Ingestion

All paths are relative to /api/public.

Observations

Deprecated: GET /observations, GET /observations/{observationId}.

Replacement: GET /v2/observations (reference).

Parameter mapping

Deprecated (v1)v2 equivalent
pagecursor (from the previous response's meta.cursor)
limit (default 50, max 100)limit (default 50, max 1,000)
GET /observations/{observationId}filter condition on the id column
name, userId, type, traceId, level, parentObservationId, environment, version, fromStartTime, toStartTimeUnchanged; always set fromStartTime and toStartTime to keep each request bounded
-fields: comma-separated field groups; defaults to core,basic

Semantic differences

  • Responses include only the requested fields groups; fields from groups you did not request are absent, not null. One exception: modelId, inputPrice, outputPrice, and totalPrice are always present but null unless the model field group is requested.
  • input/output are returned as raw strings; parse them in your pipeline when you need JSON (v1 parsed them automatically). The parseIoAsJson parameter is deprecated: omit it or set it to false; setting it to true returns a 400 error.
  • Pagination is cursor-based: pass meta.cursor from the previous response until no cursor is returned. Results are always sorted by startTime descending.
  • When the model group is requested, inputPrice, outputPrice, and totalPrice are returned as strings (e.g. "0.000005") to preserve decimal precision; cast them to a numeric type in your pipeline.

Example

# Before (v1)
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/observations?type=GENERATION&limit=10&page=1"

# After (v2)
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v2/observations?type=GENERATION&limit=10&fields=core,basic,usage&fromStartTime=2026-07-01T00:00:00Z&toStartTime=2026-07-16T00:00:00Z"

Traces

Deprecated: GET /traces, GET /traces/{traceId}.

Replacement: GET /v2/observations, grouped by traceId on the client side.

Parameter mapping

Deprecated (GET /traces)v2 equivalent
GET /traces/{traceId}traceId=<traceId>
namefilter condition on the traceName column
tagsfilter condition on the tags column (arrayOptions type)
sessionIdfilter condition on the sessionId column
userIduserId (unchanged)
fromTimestamp, toTimestampfromStartTime, toStartTime
orderByNot available; results are always sorted by startTime descending
pagecursor

Request fields=core,basic,trace_context to include the trace-level attributes traceName, tags, and release on each row.

Semantic differences

  • The response contains observation rows, not trace objects. Group rows by traceId to reconstruct trace activity.
  • v4 has no trace-level input/output. Reconstruct them from the root observation of each trace: the row with parentObservationId == null.
  • For trace-level aggregates (counts, costs, latency grouped by traceName, traceRelease, or traceVersion), use the Metrics API v2 instead of fetching and aggregating rows yourself.

Example

# Before (v1): list traces by name
curl -G \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/traces" \
  --data-urlencode "name=support-conversation" \
  --data-urlencode "limit=50"

# After (v2): fetch observation rows filtered by trace name, group by traceId
curl -G \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v2/observations" \
  --data-urlencode 'filter=[{"type":"string","column":"traceName","operator":"=","value":"support-conversation"}]' \
  --data-urlencode "fields=core,basic,io,trace_context" \
  --data-urlencode "fromStartTime=2026-07-01T00:00:00Z" \
  --data-urlencode "toStartTime=2026-07-16T00:00:00Z" \
  --data-urlencode "limit=50"

Sessions

Deprecated: GET /sessions, GET /sessions/{sessionId}. On Langfuse v4, these will return 404.

Replacement: GET /v2/observations with a filter condition on the sessionId column, grouped by sessionId on the client side.

Parameter mapping

Deprecated (GET /sessions)v2 equivalent
GET /sessions/{sessionId}filter condition on the sessionId column
fromTimestamp, toTimestampfromStartTime, toStartTime
environmentenvironment (unchanged)
pagecursor

Semantic differences

  • The response contains observation rows; a "session" is the set of rows sharing a sessionId. Group by sessionId (and within a session, by traceId) to reconstruct the session structure.
  • Like traces, sessions have no dedicated input/output object in v4. Reconstruct the conversation from the root observations of the traces within the session.
  • sessionId is a high-cardinality field: it is available for filtering in the Metrics API v2, but not for grouping.

Example

# Before (v1): fetch one session
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/sessions/chat-session-42"

# After (v2): fetch the session's observation rows
curl -G \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v2/observations" \
  --data-urlencode 'filter=[{"type":"string","column":"sessionId","operator":"=","value":"chat-session-42"}]' \
  --data-urlencode "fields=core,basic,io" \
  --data-urlencode "fromStartTime=2026-07-01T00:00:00Z" \
  --data-urlencode "toStartTime=2026-07-16T00:00:00Z"

Metrics

Deprecated: GET /metrics (v1) and GET /metrics/daily.

Replacement: GET /v2/metrics (reference).

Parameter mapping

The query object structure carries over; the key changes are inside the query:

Deprecated (v1)v2 equivalent
view: "traces"view: "observations" with trace-level dimensions (traceName, traceRelease, traceVersion)
view: "observations", "scores-numeric", "scores-categorical"Unchanged
Grouping by userId, sessionId, id, traceIdNot available; high-cardinality fields remain available as filters only
Default result sizeconfig.row_limit (default 100); set explicitly for larger result sets

Semantic differences

  • The traces view is removed. In the observations view, measures such as count, latency, totalCost, and totalTokens are calculated over observation rows, not traces. When you need trace-level counts or trace durations, use Observations API v2 and group by traceId client-side.
  • When ordering by an aggregated metric, use the returned field name in the format {aggregation}_{measure}, e.g. sum_totalCost.

Example

# Before (v1): trace count by name
curl -G \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  --data-urlencode 'query={"view":"traces","metrics":[{"measure":"count","aggregation":"count"}],"dimensions":[{"field":"name"}],"filters":[],"fromTimestamp":"2026-07-01T00:00:00Z","toTimestamp":"2026-07-16T00:00:00Z"}' \
  "https://cloud.langfuse.com/api/public/metrics"

# After (v2): observation count by trace name
curl -G \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  --data-urlencode 'query={"view":"observations","metrics":[{"measure":"count","aggregation":"count"}],"dimensions":[{"field":"traceName"}],"filters":[],"fromTimestamp":"2026-07-01T00:00:00Z","toTimestamp":"2026-07-16T00:00:00Z"}' \
  "https://cloud.langfuse.com/api/public/v2/metrics"

Daily metrics

GET /metrics/daily returned daily cost and usage timeseries broken down by model. Reproduce it with a v2 query using a daily time dimension:

curl -G \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  --data-urlencode 'query={"view":"observations","metrics":[{"measure":"count","aggregation":"count"},{"measure":"totalCost","aggregation":"sum"},{"measure":"totalTokens","aggregation":"sum"}],"dimensions":[{"field":"providedModelName"}],"timeDimension":{"granularity":"day"},"filters":[],"fromTimestamp":"2026-07-01T00:00:00Z","toTimestamp":"2026-07-16T00:00:00Z"}' \
  "https://cloud.langfuse.com/api/public/v2/metrics"

The deprecated endpoint's filters map to v2 filters entries: traceName and userId are available as filter columns; tags filters on trace tags.

Scores

Deprecated: GET /scores (v1), GET /scores/{scoreId}, GET /v2/scores, GET /v2/scores/{scoreId}. On Langfuse v4, these will return 404.

Replacement: GET /v3/scores. See the Scores API v3 announcement for background.

Parameter mapping

Deprecated (v1/v2)v3 equivalent
pagecursor (from the previous response's meta); limit max 100
GET /scores/{scoreId}, GET /v2/scores/{scoreId}id=<scoreId> filter; there is no get-by-id endpoint in v3
value + stringValue (split by type)Single value field, typed by dataType
operator + value (numeric comparison)valueMin / valueMax (inclusive bounds, require dataType=NUMERIC)
datasetRunIdexperimentId
fromTimestamp, toTimestampUnchanged names, but fromTimestamp is now inclusive and toTimestamp exclusive
userId, traceTagsRemoved; for trace-level score questions, use the Metrics API v2 score views
name, source, dataType, environment, configId, queueIdUnchanged, and now accept comma-separated lists (OR within a parameter, AND across parameters)

Semantic differences

  • One typed value field. NUMERIC scores return a number, BOOLEAN scores a boolean, and CATEGORICAL/TEXT/CORRECTION scores a string; no more parallel value/stringValue fields.
  • Field groups. Core fields are always returned; request more via fields=details,subject,annotation. The subject group replaces the flat traceId/observationId/sessionId/datasetRunId response fields with one object describing what the score is attached to (kind: trace, observation, session, or experiment).
  • Use at most one of the traceId, sessionId, and experimentId filters; they cannot be combined. observationId requires traceId alongside it (observation IDs are scoped to a trace).
  • fromTimestamp is inclusive; toTimestamp is exclusive.

Example

# Before (v2): numeric scores for a trace
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v2/scores?traceId=trace-123&dataType=NUMERIC"

# After (v3)
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v3/scores?traceId=trace-123&dataType=NUMERIC&fields=details,subject"

Dataset runs → Experiments

Deprecated: GET /datasets/{datasetName}/runs, GET /datasets/{datasetName}/runs/{runName}.

Replacement: GET /experiments and GET /experiment-items. "Dataset run" and "experiment" refer to the same concept; Langfuse is standardizing on "experiment" (terminology note).

Parameter mapping

Deprecatedv4 equivalent
{datasetName} path segmentdatasetId filter; resolve the ID via GET /v2/datasets/{datasetName}
{runName} path segmentname filter on GET /experiments
Run items (embedded in the run response)GET /experiment-items?experimentId=<id>
pagecursor; limit max 100
-fromStartTime (required on both endpoints), toStartTime

Semantic differences

  • Unlike the other deprecated reads, the dataset run reads keep working on Langfuse v4. Migrate for the richer experiments model, not because the endpoints disappear.
  • Experiments are queried by dataset ID, not name.
  • Item inputs, outputs, and expected outputs are behind the fields=io group on GET /experiment-items; scores are behind fields=scores on both endpoints. This replaces the old workaround of fetching each run item's trace to collect scores.

Example

# Before: fetch a dataset run with its items
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/datasets/my-dataset/runs/my-run"

# After: resolve the dataset ID, find the experiment, then list its items
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v2/datasets/my-dataset"

curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/experiments?fromStartTime=2026-07-01T00:00:00Z&datasetId=<dataset-id>&name=my-run&fields=core,scores"

curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/experiment-items?fromStartTime=2026-07-01T00:00:00Z&experimentId=<experiment-id>&fields=io,scores"

Ingestion

Deprecated: POST /ingestion (batched event ingestion) and the older synchronous endpoints POST /traces, POST /spans, POST /generations, POST /events.

Replacement: the OpenTelemetry endpoint POST /otel/v1/traces (OTLP/HTTP), or an upgraded SDK (Python v4.7.0+, JS/TS v5.4.0+). Set the x-langfuse-ingestion-version: 4 header on your OTEL span exporter and propagate trace attributes to all observations; see the OpenTelemetry integration guide.

Score writes via POST /scores are unaffected.


Was this page helpful?

Last edited