Langfuse v4: up to 165ร— faster ยท Read more
FaqDeprecated API migration

Migration of deprecated APIs

This page maps every deprecated Langfuse REST endpoint and the Python and JS/TS SDK methods that call it to their supported replacements. It includes 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 these endpoints through a Langfuse SDK, each section includes the methods in Python SDK v4 and JS/TS SDK v5 that call them. Deprecated Public API methods remain callable in these SDK majors, so replacing them is separate from upgrading the SDK itself. If you still need to upgrade, first follow Python v3 to v4 or JS/TS v4 to v5, then return here to replace deprecated API methods.

Still need the deprecated endpoints? They are documented in the reference section below.

This page is also served as plain markdown at https://langfuse.com/faq/all/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, then GET /experiment-itemsDataset runs
GET /dataset-run-itemsGET /experiment-itemsDataset runs
DELETE /datasets/{name}/runs/{runName}No direct replacement; DELETE /traces removes the underlying trace dataDataset runs
POST /dataset-run-itemsExperiment runner SDK or POST /otel/v1/traces with experiment attributesDataset runs
Trace and observation events sent to POST /ingestion, plus POST /traces, POST /spans, POST /generations, POST /eventsPOST /otel/v1/traces (OTLP/HTTP)Ingestion

All paths are relative to /api/public.

score-create events sent to POST /ingestion by the current SDKs are not deprecated. They remain supported after the v4 cutover.

If you access the public API from shell scripts or coding agents, the Langfuse CLI provides commands for all supported endpoints. Use at least langfuse-cli version v1.1.0 to benefit from the new endpoints.

SDK method quick reference

These mappings cover the latest Python SDK v4 and JS/TS SDK v5 method surfaces. The examples use client for a Langfuse client instance and context for an experiment-action RunnerContext. Python exposes the same generated methods asynchronously under client.async_api; use the same replacement with await. Upgrade within the current major if a replacement is missing: Scores v3 requires Python 4.8.1+ or JS/TS 5.5.0+, and experiment reads require Python 4.13.1+ or JS/TS 5.10.0+.

AreaPython SDK v4JS/TS SDK v5
Observationsclient.api.legacy.observations_v1.get_many(...) / .get(...) โ†’ client.api.observations.get_many(...)client.api.legacy.observationsV1.getMany(...) / .get(...) and client.fetchObservation(...) โ†’ client.api.observations.getMany(...)
Tracesclient.api.trace.list(...) / .get(...) โ†’ client.api.observations.get_many(...)client.api.trace.list(...) / .get(...) and client.fetchTraces(...) / .fetchTrace(...) โ†’ client.api.observations.getMany(...)
Sessionsclient.api.sessions.list(...) / .get(...) โ†’ client.api.observations.get_many(...)client.api.sessions.list(...) / .get(...) and client.fetchSessions(...) โ†’ client.api.observations.getMany(...)
Metricsclient.api.legacy.metrics_v1.metrics(...) โ†’ client.api.metrics.metrics(...). No Python v4 method calls GET /metrics/daily.client.api.legacy.metricsV1.metrics(...) โ†’ client.api.metrics.metrics(...). No JS/TS v5 method calls GET /metrics/daily.
Scoresclient.api.scores.get_many(...) / .get_by_id(...) โ†’ client.api.scores_v3.get_many_v3(...). No Python v4 method reads Scores API v1.client.api.scores.getMany(...) / .getById(...) โ†’ client.api.scoresV3.getManyV3(...). No JS/TS v5 method reads Scores API v1.
Dataset readsclient.api.dataset_run_items.list(...), client.api.datasets.get_runs(...) / .get_run(...), and client.get_dataset_runs(...) / .get_dataset_run(...) โ†’ client.api.experiments.list(...) / .list_items(...)client.api.datasetRunItems.list(...), client.api.datasets.getRuns(...) / .getRun(...), and client.getDatasetRuns(...) / .getDatasetRun(...) โ†’ client.api.experiments.list(...) / .listItems(...)
Dataset writesDirect client.api.dataset_run_items.create(...) callers should use the experiment runner. Dataset-backed client.run_experiment(...), dataset.run_experiment(...), and context.run_experiment(...) currently originate this call inside the SDK; keep the SDK updated.Direct client.api.datasetRunItems.create(...) and datasetItem.link(...) callers should use the experiment runner. Dataset-backed client.experiment.run(...), dataset.runExperiment(...), and context.runExperiment(...) currently originate this call inside the SDK; keep the SDK updated.
Dataset deletionclient.api.datasets.delete_run(...) and client.delete_dataset_run(...) โ†’ list experiment items with client.api.experiments.list_items(...), then delete their traces with client.api.trace.delete_multiple(...).client.api.datasets.deleteRun(...) โ†’ list experiment items with client.api.experiments.listItems(...), then delete their traces with client.api.trace.deleteMultiple(...).
Ingestionclient.api.ingestion.batch(...) for trace and observation events โ†’ current SDK tracing, which exports via OpenTelemetry.client.api.ingestion.batch(...) for trace and observation events โ†’ current SDK tracing, which exports via OpenTelemetry.

Observations

Deprecated: GET /observations, GET /observations/{observationId}. Langfuse Cloud serves these endpoints until November 16, 2026 (2026-11-16); migrate to v4 before this date.

Replacement: GET /v2/observations (reference).

SDK methods

SDKDeprecated callerUse instead
Python v4client.api.legacy.observations_v1.get_many(...)client.api.observations.get_many(from_start_time=..., to_start_time=...)
Python v4client.api.legacy.observations_v1.get(observation_id)client.api.observations.get_many(filter="<observation ID filter>", from_start_time=..., to_start_time=...)
JS/TS v5client.api.legacy.observationsV1.getMany(...)client.api.observations.getMany({ fromStartTime, toStartTime })
JS/TS v5client.api.legacy.observationsV1.get(observationId)client.api.observations.getMany({ filter: "<observation ID filter>", fromStartTime, toStartTime })
JS/TS v5client.fetchObservation(observationId)client.api.observations.getMany({ filter: "<observation ID filter>", fromStartTime, toStartTime })

There is no v2 single-observation getter; filter get_many / getMany by ID and take the matching row. Always bound observation queries with a time range and follow cursor pagination. client.fetchObservations(...) is not listed because in JS/TS v5 it already calls Observations API v2.

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}. Langfuse Cloud serves this endpoint until November 16, 2026 (2026-11-16); migrate to v4 before this date.

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

SDK methods

SDKDeprecated callerUse instead
Python v4client.api.trace.list(...)client.api.observations.get_many(from_start_time=..., to_start_time=...)
Python v4client.api.trace.get(trace_id)client.api.observations.get_many(trace_id=trace_id, from_start_time=..., to_start_time=...)
JS/TS v5client.api.trace.list(...)client.api.observations.getMany({ fromStartTime, toStartTime })
JS/TS v5client.fetchTraces(...)client.api.observations.getMany({ fromStartTime, toStartTime })
JS/TS v5client.api.trace.get(traceId)client.api.observations.getMany({ traceId, fromStartTime, toStartTime })
JS/TS v5client.fetchTrace(traceId)client.api.observations.getMany({ traceId, fromStartTime, toStartTime })

These replacements return observation rows, not the legacy trace response shape. Group them by traceId and reconstruct trace-level fields as described below.

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}. Langfuse Cloud serves this endpoint until November 16, 2026 (2026-11-16); migrate to v4 before this date. 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.

SDK methods

SDKDeprecated callerUse instead
Python v4client.api.sessions.list(...)client.api.observations.get_many(from_start_time=..., to_start_time=...), then group by session_id
Python v4client.api.sessions.get(session_id)client.api.observations.get_many(session_id=session_id, from_start_time=..., to_start_time=...)
JS/TS v5client.api.sessions.list(...)client.api.observations.getMany({ fromStartTime, toStartTime }), then group by sessionId
JS/TS v5client.api.sessions.get(sessionId)client.api.observations.getMany({ sessionId, fromStartTime, toStartTime })
JS/TS v5client.fetchSessions(sessionId)client.api.observations.getMany({ sessionId, fromStartTime, toStartTime })

Despite its plural name, fetchSessions(sessionId) calls the deprecated single-session endpoint. None of these replacements return the legacy session object shape.

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. Langfuse Cloud serves this endpoint until November 16, 2026 (2026-11-16); migrate to v4 before this date.

Replacement: GET /v2/metrics (reference).

SDK methods

SDKDeprecated callerUse instead
Python v4client.api.legacy.metrics_v1.metrics(query=...)client.api.metrics.metrics(query=...)
JS/TS v5client.api.legacy.metricsV1.metrics({ query })client.api.metrics.metrics({ query })

This is not only a method rename: adapt the query as described below. In particular, the removed traces view has no drop-in replacement.

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. For trace-level counts, filter on the v2-only isRootObservation = true dimension. See Logical root observations for root semantics and trace-counting edge cases. For trace durations or raw per-trace data, 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): trace count by name
curl -G \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  --data-urlencode 'query={"view":"observations","metrics":[{"measure":"count","aggregation":"count"}],"dimensions":[{"field":"traceName"}],"filters":[{"column":"isRootObservation","operator":"=","value":true,"type":"boolean"}],"fromTimestamp":"2026-07-01T00:00:00Z","toTimestamp":"2026-07-16T00:00:00Z"}' \
  "https://cloud.langfuse.com/api/public/v2/metrics"

Daily metrics

SDK methods

Python v4 and JS/TS v5 do not expose wrappers for GET /metrics/daily. Calls to this route come from direct REST usage or an older SDK. Recreate the query with client.api.metrics.metrics(...) as shown below.

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}. Langfuse Cloud serves these endpoints until November 16, 2026 (2026-11-16); migrate to v4 before this date. On Langfuse v4, these will return 404.

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

This migration applies only to score reads. Score writes remain supported through POST /scores and the current SDK score helpers. The SDKs batch score writes as score-create events through POST /ingestion; Langfuse v4 continues to accept those events after the cutover. This also covers evaluations created by the experiment runner and third-party integrations that use the current SDK score helpers. No client update or direct REST workaround is required for these score writes.

SDK methods

SDKDeprecated callerUse instead
Python v4client.api.scores.get_many(...)client.api.scores_v3.get_many_v3(...)
Python v4client.api.scores.get_by_id(score_id)client.api.scores_v3.get_many_v3(id=score_id)
JS/TS v5client.api.scores.getMany(...)client.api.scoresV3.getManyV3(...)
JS/TS v5client.api.scores.getById(scoreId)client.api.scoresV3.getManyV3({ id: scoreId })

Scores v3 requires Python SDK 4.8.1+ or JS/TS SDK 5.5.0+. It always returns a list response, including when filtering by ID.

Python v4 and JS/TS v5 do not expose read wrappers for the v1 GET /scores or GET /scores/{id} endpoints. Calls to those routes come from direct REST usage or an older SDK. Do not migrate current score-creation helpers merely because they send supported score-create events through /ingestion.

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
filter (JSON, e.g. metadata conditions)Removed; for metadata conditions, request fields=details and filter on metadata client-side
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.
  • No trace joins. v3 queries scores directly and does not return trace fields (the v2 trace field group is gone). For row-level filtering by trace properties, query Observations API v2 with the corresponding filters and fields=core,trace_context, collect the distinct trace IDs, then pass them to v3's comma-separated traceId filter.
  • Row counts can differ. v2 silently dropped scores whose referenced trace could not be found (e.g., deleted or never ingested); v3 returns every matching score, so the same query can return more rows on v3.

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: Langfuse Cloud serves these endpoints until November 16, 2026 (2026-11-16); migrate to v4 before this date.

  • GET /datasets/{datasetName}/runs
  • GET /datasets/{datasetName}/runs/{runName}
  • GET /dataset-run-items
  • DELETE /datasets/{datasetName}/runs/{runName}
  • POST /dataset-run-items

"Dataset run" and "experiment" refer to the same concept; Langfuse is standardizing on "experiment" (terminology note).

Legacy dataset endpoints: GET /api/public/datasets and GET /api/public/datasets/{name} were replaced by their /api/public/v2/datasets equivalents independently of this dataset-run migration. Python SDK v2.37.0+ and JS/TS SDK v4.0.0+ use the v2 endpoints; direct API integrations should migrate to v2 as well. The additional runs property returned by the legacy endpoints does not include v4 experiments. Use GET /experiments to list experiments. Other dataset response fields remain current.

SDK methods

Experiment reads require Python SDK 4.13.1+ or JS/TS SDK 5.10.0+. Both APIs require fromStartTime / from_start_time; use a timestamp that includes the experiments you need.

Read methods

SDKDeprecated callerUse instead
Python v4client.api.dataset_run_items.list(...)client.api.experiments.list_items(dataset_id=dataset_id, experiment_name=run_name, from_start_time=...)
JS/TS v5client.api.datasetRunItems.list(...)client.api.experiments.listItems({ datasetId, experimentName: runName, fromStartTime })
Python v4client.api.datasets.get_runs(...); client.get_dataset_runs(...)Resolve the dataset ID, then use client.api.experiments.list(dataset_id=dataset_id, from_start_time=...)
JS/TS v5client.api.datasets.getRuns(...); client.getDatasetRuns(...)Resolve the dataset ID, then use client.api.experiments.list({ datasetId, fromStartTime })
Python v4client.api.datasets.get_run(...); client.get_dataset_run(...)Use client.api.experiments.list(...) for experiment metadata and client.api.experiments.list_items(...) for its items
JS/TS v5client.api.datasets.getRun(...); client.getDatasetRun(...)Use client.api.experiments.list(...) for experiment metadata and client.api.experiments.listItems(...) for its items

If you already know both the dataset ID and experiment name, list_items / listItems can retrieve the items directly with those filters. Experiment APIs do not return the legacy combined dataset-run response shape. Follow meta.cursor until it is empty: both APIs return 50 rows by default and at most 100 rows per request.

Write methods

SDKDeprecated callerUse instead
Python v4client.api.dataset_run_items.create(...)Use client.run_experiment(...) or dataset.run_experiment(...)
Python v4Dataset-backed client.run_experiment(...), dataset.run_experiment(...), or context.run_experiment(...)No user-side code change currently removes this call; the SDK creates the legacy link internally. Keep using the runner and keep the SDK updated.
JS/TS v5client.api.datasetRunItems.create(...)Use client.experiment.run(...) or dataset.runExperiment(...)
JS/TS v5datasetItem.link(...)Use client.experiment.run(...) or dataset.runExperiment(...)
JS/TS v5Dataset-backed client.experiment.run(...), dataset.runExperiment(...), or context.runExperiment(...)No user-side code change currently removes this call; the SDK creates the legacy link internally. Keep using the runner and keep the SDK updated.

The experiment runner is the supported abstraction for creating experiment data. Current runners still call POST /dataset-run-items internally for Langfuse dataset items; moving direct callers to the runner makes the application inherit the SDK-side migration when it becomes available.

Delete methods

SDKDeprecated callerUse instead
Python v4client.api.datasets.delete_run(...); client.delete_dataset_run(...)List experiment items, collect their trace IDs, then call client.api.trace.delete_multiple(trace_ids=trace_ids)
JS/TS v5client.api.datasets.deleteRun(...)List experiment items, collect their trace IDs, then call client.api.trace.deleteMultiple({ traceIds })

There is no experiment-delete API. Follow cursor pagination through every experiment-item page, deduplicate the trace IDs, then delete them in batches of at most 1,000 per delete_multiple / deleteMultiple request. Deleting the underlying traces also deletes their observations and related scores, so confirm that this broader deletion matches your intent.

Read experiment data

Use GET /experiments to list experiments or find one by its dataset ID and name. Use GET /experiment-items?experimentId=<id> to retrieve the items belonging to an experiment.

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 responseGET /experiment-items?experimentId=<id>
GET /dataset-run-items?datasetId=<id>&runName=<name>Resolve the experiment with GET /experiments, then list its items
pagecursor; limit max 100
-fromStartTime (required on both endpoints), toStartTime

Semantic differences

  • 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.

Create experiment data

For Python and JS/TS, use the Experiment runner SDK. It applies the required experiment semantics automatically and is the recommended replacement for POST /dataset-run-items.

The experiment runner's Evaluation results use the supported SDK score-write path. Although the SDK batches them as score-create events through POST /ingestion, those events remain accepted after the v4 cutover; the legacy ingestion deprecation applies only to trace and observation events.

For other languages, send experiment traces to POST /otel/v1/traces and apply the required experiment attributes.

Delete experiment data

Langfuse v4 does not provide an endpoint that deletes only an experiment.

This is not semantically equivalent to the deprecated endpoint: deleting the traces also deletes their observations and related scores. See Data Deletion for details.

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 for trace and observation ingestion: trace and observation event types sent to POST /ingestion, and the older synchronous endpoints POST /traces, POST /spans, POST /generations, POST /events. Langfuse Cloud serves these trace-ingestion paths until November 16, 2026 (2026-11-16); migrate to v4 before this date.

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.

SDK methods

SDKDeprecated callerUse instead
Python v4client.api.ingestion.batch(...) with trace or observation eventsPython SDK 4.7.0+ tracing and instrumentation, which export through OpenTelemetry
JS/TS v5client.api.ingestion.batch(...) with trace or observation eventsJS/TS SDK 5.4.0+ tracing and instrumentation, which export through OpenTelemetry

Score writes are unaffected. Direct REST clients can continue using POST /scores. Current Python and JS/TS SDKs intentionally batch score writes as score-create events through POST /ingestion; Langfuse v4 continues to accept that event type after November 16, 2026 (2026-11-16). No SDK release that reroutes score writes to POST /scores is required for compatibility.

Deprecated endpoints

These endpoints are deprecated and receive security patches only, no other fixes or new functionality. Langfuse Cloud serves these endpoints until November 16, 2026 (2026-11-16); migrate to v4 before this date. All paths are relative to /api/public.

Deprecated endpoint(s)ParametersReplacement
GET /traces, /traces/{id}API referenceObservations API v2, filtered by traceId
GET /observations, /observations/{id}API referenceObservations API v2
GET /sessions, /sessions/{id}API referenceObservations API v2, filtered by sessionId
GET /scores, /v2/scores (+ /{id})API referenceScores API v3
GET /metricsDocumented belowMetrics API v2
GET /metrics/dailyDocumented belowMetrics API v2
GET /datasets/{name}/runs, /datasets/{name}/runs/{runName}API referenceGET /experiments, then GET /experiment-items
GET /dataset-run-itemsAPI referenceGET /experiment-items
DELETE /datasets/{name}/runs/{runName}API referenceNo direct replacement; optionally list the experiment items and delete their traces
POST /dataset-run-itemsAPI referenceExperiment runner SDK (recommended for Python and JS/TS), or POST /otel/v1/traces with experiment attributes for other languages
Trace and observation events sent to POST /ingestionAPI referenceOpenTelemetry ingestion; score-create and sdk-log events remain supported
POST /traces, /spans, /generations, /eventsNot in the API referenceOpenTelemetry ingestion

Metrics API v1

GET /api/public/metrics

The v1 Metrics API supports querying across different views (traces, observations, scores) and allows you to:

  • Select specific dimensions to group your data
  • Apply multiple metrics with different aggregation methods
  • Filter data based on metadata, timestamps, and other properties
  • Analyze data across time with customizable granularity
  • Order results

Langfuse Cloud serves this endpoint until November 16, 2026 (2026-11-16); migrate to v4 before this date.

Replacement: Metrics API v2.

Query Parameters

The v1 API accepts a JSON query object passed as a URL-encoded parameter:

ParameterTypeDescription
queryJSON stringThe encoded query object defining what metrics to retrieve

Query Object Structure

FieldTypeRequiredDescription
viewstringYesThe data view to query: "traces", "observations", "scores-numeric", "scores-categorical", or "scores-boolean"
dimensionsarrayNoArray of dimension objects to group by, e.g. [{ "field": "name" }]
metricsarrayYesArray of metric objects to calculate, e.g. [{ "measure": "latency", "aggregation": "p95" }]
filtersarrayNoArray of filter objects to narrow results, e.g. [{ "column": "metadata", "operator": "contains", "key": "customKey", "value": "customValue", "type": "stringObject" }]
timeDimensionobjectNoConfiguration for time-based analysis, e.g. { "granularity": "day" }
fromTimestampstringYesISO timestamp for the start of the query period
toTimestampstringYesISO timestamp for the end of the query period
orderByarrayNoSpecification for result ordering, e.g. [{ "field": "name", "direction": "asc" }]

Dimension Object Structure

{ "field": "name" }

Metric Object Structure

{ "measure": "count", "aggregation": "count" }

Common measure types include:

  • count - Count of records
  • latency - Duration/latency metrics

Aggregation types include:

  • sum - Sum of values
  • avg - Average of values
  • count - Count of records
  • max - Maximum value
  • min - Minimum value
  • p50 - 50th percentile
  • p75 - 75th percentile
  • p90 - 90th percentile
  • p95 - 95th percentile
  • p99 - 99th percentile

Filter Object Structure

{
  "column": "metadata",
  "operator": "contains",
  "key": "customKey",
  "value": "customValue",
  "type": "stringObject"
}

Time Dimension Object

{
  "granularity": "day"
}

Supported granularities include: hour, day, week, month, and auto.

Example

Here's an example of querying the number of traces grouped by name:

curl \
-H "Authorization: Basic <BASIC AUTH HEADER>" \
-G \
--data-urlencode 'query={
  "view": "traces",
  "metrics": [{"measure": "count", "aggregation": "count"}],
  "dimensions": [{"field": "name"}],
  "filters": [],
  "fromTimestamp": "2025-05-01T00:00:00Z",
  "toTimestamp": "2025-05-13T00:00:00Z"
}' \
https://cloud.langfuse.com/api/public/metrics
query = """
{
  "view": "traces",
  "metrics": [{"measure": "count", "aggregation": "count"}],
  "dimensions": [{"field": "name"}],
  "filters": [],
  "fromTimestamp": "2025-05-01T00:00:00Z",
  "toTimestamp": "2025-05-13T00:00:00Z"
}
"""

langfuse.api.legacy.metrics_v1.metrics(query = query)

Response:

{
  "data": [
    { "name": "trace-test-2", "count_count": "10" },
    { "name": "trace-test-3", "count_count": "5" },
    { "name": "trace-test-1", "count_count": "3" }
  ]
}

Data Model

The v1 Metrics API provides access to several data views, each with its own set of dimensions and metrics you can query. This section outlines the available options for each view.

Available Views

ViewDescription
tracesQuery data at the trace level
observationsQuery data at the observation level
scores-numericQuery numeric scores
scores-categoricalQuery categorical (string) scores
scores-booleanQuery boolean scores

Trace Dimensions

DimensionTypeDescription
idstringTrace ID
namestringTrace name
tagsstring[]Trace tags
userIdstringUser ID associated with the trace
sessionIdstringSession ID associated with the trace
releasestringRelease tag
versionstringVersion tag
environmentstringEnvironment (e.g., production, staging)
observationNamestringName of related observations
scoreNamestringName of related scores

Trace Metrics

MetricDescription
countCount of traces
observationsCountCount of observations within traces
scoresCountCount of scores within traces
latencyTrace duration in milliseconds
totalTokensTotal tokens used in the trace
totalCostTotal cost of the trace

Observation Dimensions

DimensionTypeDescription
idstringObservation ID
traceIdstringAssociated trace ID
traceNamestringName of the parent trace
environmentstringEnvironment (e.g., production, staging)
parentObservationIdstringID of parent observation
typestringObservation type
namestringObservation name
levelstringLog level
versionstringVersion
providedModelNamestringModel name
promptNamestringPrompt name
promptVersionstringPrompt version
userIdstringUser ID from parent trace
sessionIdstringSession ID from parent trace
traceReleasestringRelease from parent trace
traceVersionstringVersion from parent trace
scoreNamestringRelated score name

Observation Metrics

MetricDescription
countCount of observations
latencyObservation duration in milliseconds
totalTokensTotal tokens used
totalCostTotal cost
timeToFirstTokenTime to first token in milliseconds
countScoresCount of related scores

Score Dimensions (Common)

DimensionTypeDescription
idstringScore ID
namestringScore name
environmentstringEnvironment
sourcestringScore source
dataTypestringData type
traceIdstringRelated trace ID
traceNamestringRelated trace name
userIdstringUser ID from trace
sessionIdstringSession ID from trace
observationIdstringRelated observation ID
observationNamestringRelated observation name
observationModelNamestringModel used in related observation
observationPromptNamestringPrompt name used in related observation
observationPromptVersionstringPrompt version used in related observation
configIdstringConfiguration ID

Score Metrics

Numeric Scores
MetricDescription
countCount of scores
valueNumeric score value
Boolean Scores
MetricDescription
countCount of scores
valueNumeric score value, where 0 is false and 1 is true. Use the avg aggregation to return the true rate

Boolean scores have an additional dimension:

DimensionTypeDescription
booleanValuebooleanBoolean value of the score for grouping and filtering
Categorical Scores
MetricDescription
countCount of scores

Categorical scores have an additional dimension:

DimensionTypeDescription
stringValuestringString value of the categorical score

Daily Metrics API

GET /api/public/metrics/daily

The Daily Metrics API returns aggregated daily usage and cost metrics for downstream use in analytics, billing, and rate limiting, and allows you to:

  • Retrieve daily timeseries of cost in USD and trace and observation counts
  • Break down usage (e.g. tokens, split by input and output) and cost by model name
  • Filter by trace name, user, or tags

Replacement: Metrics API v2 with a daily time dimension.

Query Parameters

All parameters are optional:

ParameterTypeDescription
traceNamestringFilter by trace name, commonly the application type depending on how you use trace names
userIdstringFilter by user
tagsstring[]Filter by tags
fromTimestampdatetimeStart of the date range
toTimestampdatetimeEnd of the date range
page, limitnumberPage-based pagination

Example

GET /api/public/metrics/daily?traceName=my-copilot&userId=john&limit=2
{
  "data": [
    {
      "date": "2024-02-18",
      "countTraces": 1500,
      "countObservations": 3000,
      "totalCost": 102.19,
      "usage": [
        {
          "model": "llama2",
          "inputUsage": 1200,
          "outputUsage": 1300,
          "totalUsage": 2500,
          "countTraces": 1000,
          "countObservations": 2000,
          "totalCost": 50.19
        },
        {
          "model": "gpt-4",
          "inputUsage": 500,
          "outputUsage": 550,
          "totalUsage": 1050,
          "countTraces": 500,
          "countObservations": 1000,
          "totalCost": 52.0
        }
      ]
    },
    {
      "date": "2024-02-17",
      "countTraces": 1250,
      "countObservations": 2500,
      "totalCost": 250.0,
      "usage": [
        {
          "model": "llama2",
          "inputUsage": 1000,
          "outputUsage": 1100,
          "totalUsage": 2100,
          "countTraces": 1250,
          "countObservations": 2500,
          "totalCost": 250.0
        }
      ]
    }
  ],
  "meta": {
    "page": 1,
    "limit": 2,
    "totalItems": 60,
    "totalPages": 30
  }
}

Was this page helpful?

Last edited