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 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 endpoint | Replacement | Details |
|---|---|---|
GET /observations, GET /observations/{id} | GET /v2/observations | Observations |
GET /traces, GET /traces/{id} | GET /v2/observations, filtered by traceId | Traces |
GET /sessions, GET /sessions/{id} | GET /v2/observations, filtered by sessionId | Sessions |
GET /metrics, GET /metrics/daily | GET /v2/metrics | Metrics |
GET /scores, GET /scores/{id}, GET /v2/scores, GET /v2/scores/{id} | GET /v3/scores | Scores |
GET /datasets/{name}/runs, GET /datasets/{name}/runs/{runName} | GET /experiments, then GET /experiment-items | Dataset runs |
GET /dataset-run-items | GET /experiment-items | Dataset runs |
DELETE /datasets/{name}/runs/{runName} | No direct replacement; DELETE /traces removes the underlying trace data | Dataset runs |
POST /dataset-run-items | Experiment runner SDK or POST /otel/v1/traces with experiment attributes | Dataset runs |
POST /ingestion, POST /traces, POST /spans, POST /generations, POST /events | POST /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 |
|---|---|
page | cursor (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, toStartTime | Unchanged; 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
fieldsgroups; fields from groups you did not request are absent, notnull. One exception:modelId,inputPrice,outputPrice, andtotalPriceare always present butnullunless themodelfield group is requested. input/outputare returned as raw strings; parse them in your pipeline when you need JSON (v1 parsed them automatically). TheparseIoAsJsonparameter is deprecated: omit it or set it tofalse; setting it totruereturns a400error.- Pagination is cursor-based: pass
meta.cursorfrom the previous response until no cursor is returned. Results are always sorted bystartTimedescending. - When the
modelgroup is requested,inputPrice,outputPrice, andtotalPriceare 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> |
name | filter condition on the traceName column |
tags | filter condition on the tags column (arrayOptions type) |
sessionId | filter condition on the sessionId column |
userId | userId (unchanged) |
fromTimestamp, toTimestamp | fromStartTime, toStartTime |
orderBy | Not available; results are always sorted by startTime descending |
page | cursor |
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
traceIdto reconstruct trace activity. - v4 has no trace-level
input/output. Reconstruct them from the root observation of each trace: the row withparentObservationId == null. - For trace-level aggregates (counts, costs, latency grouped by
traceName,traceRelease, ortraceVersion), 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, toTimestamp | fromStartTime, toStartTime |
environment | environment (unchanged) |
page | cursor |
Semantic differences
- The response contains observation rows; a "session" is the set of rows sharing a
sessionId. Group bysessionId(and within a session, bytraceId) 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.
sessionIdis 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, traceId | Not available; high-cardinality fields remain available as filters only |
| Default result size | config.row_limit (default 100); set explicitly for larger result sets |
Semantic differences
- The
tracesview is removed. In theobservationsview, measures such ascount,latency,totalCost, andtotalTokensare calculated over observation rows, not traces. When you need trace-level counts or trace durations, use Observations API v2 and group bytraceIdclient-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 |
|---|---|
page | cursor (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) |
datasetRunId | experimentId |
fromTimestamp, toTimestamp | Unchanged names, but fromTimestamp is now inclusive and toTimestamp exclusive |
userId, traceTags | Removed; 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, queueId | Unchanged, and now accept comma-separated lists (OR within a parameter, AND across parameters) |
Semantic differences
- One typed
valuefield.NUMERICscores return a number,BOOLEANscores a boolean, andCATEGORICAL/TEXT/CORRECTIONscores a string; no more parallelvalue/stringValuefields. - Field groups. Core fields are always returned; request more via
fields=details,subject,annotation. Thesubjectgroup replaces the flattraceId/observationId/sessionId/datasetRunIdresponse fields with one object describing what the score is attached to (kind:trace,observation,session, orexperiment). - Use at most one of the
traceId,sessionId, andexperimentIdfilters; they cannot be combined.observationIdrequirestraceIdalongside it (observation IDs are scoped to a trace). fromTimestampis inclusive;toTimestampis exclusive.- No trace joins. v3 queries scores directly and does not return trace fields (the v2
tracefield group is gone). For row-level filtering by trace properties, query the traces API withuserId/tagsfilters first to collect the matching trace IDs, then pass them to v3's comma-separatedtraceIdfilter. - 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:
GET /datasets/{datasetName}/runsGET /datasets/{datasetName}/runs/{runName}GET /dataset-run-itemsDELETE /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.
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
| Deprecated | v4 equivalent |
|---|---|
{datasetName} path segment | datasetId filter; resolve the ID via GET /v2/datasets/{datasetName} |
{runName} path segment | name filter on GET /experiments |
| Run items embedded in the run response | GET /experiment-items?experimentId=<id> |
GET /dataset-run-items?datasetId=<id>&runName=<name> | Resolve the experiment with GET /experiments, then list its items |
page | cursor; 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=iogroup onGET /experiment-items; scores are behindfields=scoreson 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.
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. To delete its tracing data, list the experiment items with GET /experiment-items?fromStartTime=<timestamp>&experimentId=<id>, collect their traceId values, and pass them to DELETE /traces. The trace deletion endpoint is not deprecated.
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: 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.
Deprecated endpoints
These endpoints are deprecated and receive security patches only, no other fixes or new functionality.
All paths are relative to /api/public.
Metrics API v1
GET /api/public/metricsThe 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
Replacement: Metrics API v2.
Query Parameters
The v1 API accepts a JSON query object passed as a URL-encoded parameter:
| Parameter | Type | Description |
|---|---|---|
query | JSON string | The encoded query object defining what metrics to retrieve |
Query Object Structure
| Field | Type | Required | Description |
|---|---|---|---|
view | string | Yes | The data view to query: "traces", "observations", "scores-numeric", "scores-categorical", or "scores-boolean" |
dimensions | array | No | Array of dimension objects to group by, e.g. [{ "field": "name" }] |
metrics | array | Yes | Array of metric objects to calculate, e.g. [{ "measure": "latency", "aggregation": "p95" }] |
filters | array | No | Array of filter objects to narrow results, e.g. [{ "column": "metadata", "operator": "contains", "key": "customKey", "value": "customValue", "type": "stringObject" }] |
timeDimension | object | No | Configuration for time-based analysis, e.g. { "granularity": "day" } |
fromTimestamp | string | Yes | ISO timestamp for the start of the query period |
toTimestamp | string | Yes | ISO timestamp for the end of the query period |
orderBy | array | No | Specification 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 recordslatency- Duration/latency metrics
Aggregation types include:
sum- Sum of valuesavg- Average of valuescount- Count of recordsmax- Maximum valuemin- Minimum valuep50- 50th percentilep75- 75th percentilep90- 90th percentilep95- 95th percentilep99- 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/metricsquery = """
{
"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
| View | Description |
|---|---|
traces | Query data at the trace level |
observations | Query data at the observation level |
scores-numeric | Query numeric scores |
scores-categorical | Query categorical (string) scores |
scores-boolean | Query boolean scores |
Trace Dimensions
| Dimension | Type | Description |
|---|---|---|
id | string | Trace ID |
name | string | Trace name |
tags | string[] | Trace tags |
userId | string | User ID associated with the trace |
sessionId | string | Session ID associated with the trace |
release | string | Release tag |
version | string | Version tag |
environment | string | Environment (e.g., production, staging) |
observationName | string | Name of related observations |
scoreName | string | Name of related scores |
Trace Metrics
| Metric | Description |
|---|---|
count | Count of traces |
observationsCount | Count of observations within traces |
scoresCount | Count of scores within traces |
latency | Trace duration in milliseconds |
totalTokens | Total tokens used in the trace |
totalCost | Total cost of the trace |
Observation Dimensions
| Dimension | Type | Description |
|---|---|---|
id | string | Observation ID |
traceId | string | Associated trace ID |
traceName | string | Name of the parent trace |
environment | string | Environment (e.g., production, staging) |
parentObservationId | string | ID of parent observation |
type | string | Observation type |
name | string | Observation name |
level | string | Log level |
version | string | Version |
providedModelName | string | Model name |
promptName | string | Prompt name |
promptVersion | string | Prompt version |
userId | string | User ID from parent trace |
sessionId | string | Session ID from parent trace |
traceRelease | string | Release from parent trace |
traceVersion | string | Version from parent trace |
scoreName | string | Related score name |
Observation Metrics
| Metric | Description |
|---|---|
count | Count of observations |
latency | Observation duration in milliseconds |
totalTokens | Total tokens used |
totalCost | Total cost |
timeToFirstToken | Time to first token in milliseconds |
countScores | Count of related scores |
Score Dimensions (Common)
| Dimension | Type | Description |
|---|---|---|
id | string | Score ID |
name | string | Score name |
environment | string | Environment |
source | string | Score source |
dataType | string | Data type |
traceId | string | Related trace ID |
traceName | string | Related trace name |
userId | string | User ID from trace |
sessionId | string | Session ID from trace |
observationId | string | Related observation ID |
observationName | string | Related observation name |
observationModelName | string | Model used in related observation |
observationPromptName | string | Prompt name used in related observation |
observationPromptVersion | string | Prompt version used in related observation |
configId | string | Configuration ID |
Score Metrics
Numeric Scores
| Metric | Description |
|---|---|
count | Count of scores |
value | Numeric score value |
Boolean Scores
| Metric | Description |
|---|---|
count | Count of scores |
value | Numeric 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:
| Dimension | Type | Description |
|---|---|---|
booleanValue | boolean | Boolean value of the score for grouping and filtering |
Categorical Scores
| Metric | Description |
|---|---|
count | Count of scores |
Categorical scores have an additional dimension:
| Dimension | Type | Description |
|---|---|---|
stringValue | string | String value of the categorical score |
Daily Metrics API
GET /api/public/metrics/dailyThe 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:
| Parameter | Type | Description |
|---|---|---|
traceName | string | Filter by trace name, commonly the application type depending on how you use trace names |
userId | string | Filter by user |
tags | string[] | Filter by tags |
fromTimestamp | datetime | Start of the date range |
toTimestamp | datetime | End of the date range |
page, limit | number | Page-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
}
}Last edited