DocsScores API

Scores API

The Scores API allows you to retrieve score data (evaluations, annotations, and API-ingested scores) from Langfuse for use in custom workflows, evaluation pipelines, and analytics.

If you need aggregated score metrics (e.g., average scores grouped by trace name, user, or time period) rather than individual scores, the Metrics API is designed for this and avoids the need to fetch and aggregate raw data yourself.

For general information about API authentication, base URLs, and SDK access, see the Public API documentation.

This page covers reading scores. Scores are created via POST /api/public/scores or the SDK helpers — see scores via API/SDK. Migrating from the deprecated v2 read endpoints? Jump to Migrating from Scores API v2.

Scores API v3

Where is this feature available?
  • Hobby
    Available
  • Core
    Available
  • Pro
    Available
  • Enterprise
    Available
  • Self Hosted
    Available
GET /api/public/v3/scores

On self-hosted deployments, the v3 endpoint is available from Langfuse v3.179.0.

The Scores API queries scores directly instead of joining trace data, which keeps response times predictable at any volume. Responses carry a single typed value field, and results are paginated with a cursor.

Typed value Field

Every score has a single value field whose type follows dataType — no decoding of booleans from 1/0 or looking up category strings:

dataTypevalue typeNotes
NUMERICnumber
BOOLEANboolean
CATEGORICALstringThe category
TEXTstring
CORRECTIONstringEmpty string if no correction

If your pipeline handles mixed score types, branch on dataType.

Field Groups

Responses always include a lean core — id, projectId, name, value, dataType, source, timestamp, environment, createdAt, updatedAt — and you opt into additional groups via a comma-separated fields parameter:

?fields=details,subject,annotation
GroupFields
coreAlways included (see above)
detailscomment, configId, metadata
subjectsubject (the entity the score is attached to, see below)
annotationauthorUserId, queueId

Unknown group names return HTTP 400.

subject Object

Every score is attached to exactly one entity. Request the subject field group to see which one — it is discriminated by kind:

{ "kind": "observation", "id": "obs-1", "traceId": "trace-1" }
  • kind: "trace"id is the trace ID
  • kind: "observation"id is the observation ID; includes the parent traceId
  • kind: "session"id is the session ID
  • kind: "experiment"id is the dataset run ID

Cursor-Based Pagination

  1. Make your initial request with a limit parameter (default 50, max 100)
  2. If more results exist, the response includes a cursor in the meta object
  3. Pass this cursor via the cursor parameter in your next request, repeating the same filter parameters as the initial request — the cursor encodes only the read position, not your query
  4. Repeat until no cursor is returned (you've reached the end)

The response contains no total counts — iterate the cursor until it is absent. For recurring full exports to your data warehouse, use the scheduled blob storage export instead of paginating through the API.

Filtering

  • Multi-value filters: most filters accept comma-separated lists — id, name, source, dataType, environment, configId, queueId, authorUserId, traceId, sessionId, observationId, experimentId. Values within one parameter are OR-ed, parameters are AND-ed: name=hallucination,toxicity&source=EVAL returns eval scores named either hallucination or toxicity.
  • Value filters: use value for exact matches (comma-separated, requires a single dataType of NUMERIC, BOOLEAN, or CATEGORICAL) or valueMin/valueMax for inclusive numeric range bounds (require dataType=NUMERIC).
  • Mutual exclusivity: traceId, sessionId, and experimentId are mutually exclusive. observationId requires traceId because observation IDs are scoped to a trace.
  • Case-insensitive enums: source and dataType accept any casing (numeric and NUMERIC are equivalent).
  • Timestamp bounds: fromTimestamp is inclusive, toTimestamp is exclusive.

Invalid filter combinations are rejected with HTTP 400 rather than silently ignored.

Common Use Cases

Pulling failing evals:

curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v3/scores?name=hallucination,toxicity&dataType=NUMERIC&valueMax=0.5"

Getting scores for specific traces, including what they are attached to:

curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v3/scores?traceId=trace-1,trace-2&fields=details,subject"

Fetching a single score by ID:

curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v3/scores?id=your-score-id"

Paginating through results:

# First request
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v3/scores?fromTimestamp=2026-06-01T00:00:00Z&limit=100"

# Response includes: "meta": { "limit": 100, "cursor": "eyJsYXN0..." }

# Next request with cursor
curl \
  -H "Authorization: Basic <BASIC AUTH HEADER>" \
  "https://cloud.langfuse.com/api/public/v3/scores?fromTimestamp=2026-06-01T00:00:00Z&limit=100&cursor=eyJsYXN0..."

SDK Access

The generated SDK clients expose the v3 endpoint directly. Score creation uses separate SDK helpers (e.g. create_score in Python) — this client is for reads.

from langfuse import get_client

langfuse = get_client()

# v3 (recommended)
scores = langfuse.api.scores_v3.get_many_v3(
    name="hallucination,toxicity",
    data_type="NUMERIC",
    value_max=0.5,
    fields="details,subject",
    limit=100,
)

# v2 (deprecated): langfuse.api.scores.get_many(...)

Also available as async via langfuse.async_api.scores_v3.get_many_v3(...).

import { LangfuseClient } from "@langfuse/client";

const langfuse = new LangfuseClient();

// v3 (recommended)
const scores = await langfuse.api.scoresV3.getManyV3({
  name: "hallucination,toxicity",
  dataType: "NUMERIC",
  valueMax: 0.5,
  fields: "details,subject",
  limit: 100,
});

// v2 (deprecated): langfuse.api.scores.getMany(...)

Parameters

ParameterTypeDescription
limitintegerNumber of items per page. Defaults to 50, max 100 (larger values return HTTP 400)
cursorstringURL-safe base64 cursor for pagination (from previous response)
fieldsstringComma-separated field groups to include in addition to core: details, subject, annotation
idstringComma-separated list of score IDs
namestringComma-separated list of score names
sourcestringComma-separated list of score sources (API, ANNOTATION, EVAL), case-insensitive
dataTypestringComma-separated list of data types (NUMERIC, BOOLEAN, CATEGORICAL, TEXT, CORRECTION), case-insensitive. Must be a single value when combined with value, valueMin, or valueMax
environmentstringComma-separated list of environments
configIdstringComma-separated list of score config IDs
queueIdstringComma-separated list of annotation queue IDs
authorUserIdstringComma-separated list of author user IDs
valuestringComma-separated list of exact values. Requires a single dataType of NUMERIC, BOOLEAN, or CATEGORICAL. For BOOLEAN pass true or false; for NUMERIC each value must be a finite number
valueMinnumberInclusive lower bound on the numeric value. Requires dataType=NUMERIC
valueMaxnumberInclusive upper bound on the numeric value. Requires dataType=NUMERIC
traceIdstringComma-separated list of trace IDs. Mutually exclusive with sessionId, experimentId
sessionIdstringComma-separated list of session IDs. Mutually exclusive with traceId, observationId, experimentId
observationIdstringComma-separated list of observation IDs. Requires traceId
experimentIdstringComma-separated list of dataset run IDs (experiment IDs). Mutually exclusive with traceId, sessionId, observationId
fromTimestampdatetimeInclusive lower bound on the score timestamp
toTimestampdatetimeExclusive upper bound on the score timestamp

Sample Response

With fields=details,subject,annotation:

{
  "data": [
    {
      "id": "score-1",
      "projectId": "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
      "name": "hallucination",
      "value": 0.25,
      "dataType": "NUMERIC",
      "source": "EVAL",
      "timestamp": "2026-06-15T10:30:00Z",
      "environment": "default",
      "createdAt": "2026-06-15T10:30:01Z",
      "updatedAt": "2026-06-15T10:30:01Z",
      "comment": "Low hallucination risk",
      "configId": null,
      "metadata": {},
      "authorUserId": null,
      "queueId": null,
      "subject": {
        "kind": "observation",
        "id": "support-chat-7-950dc53a-gen",
        "traceId": "support-chat-7-950dc53a"
      }
    },
    {
      "id": "score-2",
      "projectId": "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
      "name": "helpful",
      "value": true,
      "dataType": "BOOLEAN",
      "source": "ANNOTATION",
      "timestamp": "2026-06-15T11:00:00Z",
      "environment": "default",
      "createdAt": "2026-06-15T11:00:02Z",
      "updatedAt": "2026-06-15T11:00:02Z",
      "comment": null,
      "configId": "cfg-1",
      "metadata": {},
      "authorUserId": "user-123",
      "queueId": "queue-1",
      "subject": {
        "kind": "trace",
        "id": "support-chat-7-950dc53a"
      }
    }
  ],
  "meta": {
    "limit": 50,
    "cursor": "eyJ2IjoxLCJsYXN0VGltZXN0YW1wIjoiMjAyNi0wNi0xNVQxMTowMDowMFoiLCJsYXN0SWQiOiJzY29yZS0yIn0"
  }
}

API Reference: See the full v3 Scores API Reference for all available parameters, response schemas, and interactive examples.

Migrating from Scores API v2

v2 read deprecation

The v2 score read endpoints are deprecated. Self-hosted deployments on Langfuse v4 and later do not include them — migrate to v3 before upgrading. On Langfuse Cloud they remain available for a transition period.

Full endpoint mapping — only reads change, the write endpoints stay as they are:

Existing usageRecommended replacement
List scores with GET /api/public/v2/scoresUse GET /api/public/v3/scores
Fetch one score with GET /api/public/v2/scores/{scoreId}Use GET /api/public/v3/scores?id=<scoreId> — v3 has no get-by-id endpoint; the id filter replaces it
Create scores with POST /api/public/scoresUnchanged
Delete scores with DELETE /api/public/scores/{scoreId}Unchanged

In the SDKs, replace langfuse.api.scores.get_many(...) (Python) / langfuse.api.scores.getMany(...) (JS/TS) with the v3 client shown under SDK access.

Response Changes

One typed value field. The v2 API split score values across a numeric value and a separate stringValue field. v3 returns a single value typed by dataType (see above):

dataTypev2 behaviorv3 value
NUMERICvalue (number)number
BOOLEANvalue (1/0) plus stringValue ("True"/"False")boolean
CATEGORICALvalue (numeric category mapping from the score config; not meaningful without one) plus stringValue (category string)string
TEXTstringValue onlystring
CORRECTIONvalue (always 0) plus stringValue (correction content)string

When migrating, read value directly and branch on dataType if your pipeline handles mixed score types.

subject object replaces flat reference fields. v2 score objects carried flat, nullable traceId, observationId, sessionId, and datasetRunId fields. v3 replaces them with the opt-in subject object (request fields=subject); dataset runs appear as kind: "experiment" (v2's datasetRunId).

Re-partitioned field groups. v2 had two field groups, score and trace, both returned by default. v3 always returns the core fields and offers details, subject, and annotation as opt-ins. The v2 trace group (the trace's userId, tags, environment, sessionId) has no v3 equivalent because v3 does not join trace data — see removed capabilities.

Query Changes

  • Cursor pagination replaces offset pagination. v2's page parameter and totalItems/totalPages meta are gone — pass limit and follow the cursor instead.
  • operator is replaced by typed value filters. Use value (exact multi-match) or valueMin/valueMax (numeric range).
  • Renamed parameters: scoreIdsid, datasetRunIdexperimentId (same comma-separated semantics).
  • Stricter validation: traceId/sessionId/experimentId are mutually exclusive and observationId requires traceId; invalid combinations return HTTP 400 instead of being silently ignored.

Removed Capabilities and Workarounds

v2 capabilityv3 replacement
userId / traceTags filtersRemoved (HTTP 400) — v3 does not join trace data by design. See workaround below.
operator parameterUse value (exact multi-match) or valueMin/valueMax (numeric range).
Raw JSON filter parameterMap each condition to the typed query parameters. See metadata note below.
totalItems / totalPages in metaRemoved by design — iterate the cursor.

Filtering by trace properties (userId, traceTags):

  • Row-level: query the traces API with userId/tags filters first to collect the matching trace IDs, then pass them to v3's multi-value traceId filter (e.g. traceId=t-1,t-2,t-3).
  • Aggregates: if you only need aggregate score metrics per user, tag, or other trace-level dimensions, use the Metrics API instead — it supports trace-level dimensions and filters directly.

Filtering by score metadata: the v2 JSON filter parameter supported metadata key-value conditions (stringObject). v3 has no metadata filter — request fields=details and filter on metadata client-side.

Row-count differences after migration: because v2 joins trace data by default, it silently drops trace-level scores whose referenced trace cannot be found (e.g., the trace was deleted or never ingested). v3 queries scores directly and returns every matching score, so v3 can return rows that the same query on v2 did not.


Was this page helpful?

Last edited