Observations API
The Observations API allows you to retrieve observation data (spans, generations, events) from Neural Inverse for use in custom workflows, evaluation pipelines, and analytics.
If you need aggregated metrics (e.g., total cost, token counts, or trace volumes grouped by user, model, or time period) rather than individual observations, 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.
Older trace and observation read APIs remain available, but are not recommended as the default for new data extraction workflows because they are less performant at scale. Use Observations API v2 for row-level data extraction.
Observations API v2
Cloud-only: The v2 Observations API is only available on Neural Inverse Cloud. We are working on a robust migration path for self-hosted deployments.
Data availability: Data from older SDKs (langfuse-python < 4.0.0, langfuse-js < 5.0.0) or direct OpenTelemetry exporters that do not send x-langfuse-ingestion-version: 4 can be delayed by up to 10 minutes on v2 endpoints. Upgrade to Python SDK v4 or JS/TS SDK v5, or set that header on your OTEL span exporter, to see new data in real time.
GET /api/public/v2/observationsThe v2 Observations API is a redesigned endpoint optimized for high-performance data retrieval. It addresses the performance bottlenecks of the v1 API by minimizing the work Neural Inverse has to perform per query.
Upgrade from older trace and observation reads
| Existing usage | Recommended replacement |
|---|---|
List traces with GET /api/public/traces | Use GET /api/public/v2/observations?fromStartTime=<from>&toStartTime=<to> and group rows by traceId |
Fetch one trace with GET /api/public/traces/{traceId} | Use GET /api/public/v2/observations?traceId=<traceId>&fromStartTime=<from>&toStartTime=<to> |
List observations with GET /api/public/observations | Use GET /api/public/v2/observations?fromStartTime=<from>&toStartTime=<to> |
Fetch one observation with GET /api/public/observations/{observationId} | Use GET /api/public/v2/observations?filter=<id filter>&fromStartTime=<from>&toStartTime=<to> |
Always include fromStartTime and toStartTime to keep each request bounded.
The v2 Observations API returns observation rows, not full trace objects. Group rows by traceId when you need to reconstruct trace activity, and use Metrics API v2 for aggregate reporting with trace-level dimensions such as traceName, traceRelease, or traceVersion. For single-observation lookups, pass a URL-encoded filter condition on the id column; see the v2 Observations API Reference for the filter schema.
Key Improvements
1. Selective Field Retrieval
The v1 API returns complete rows with all fields (input/output, usage, metadata, etc.), forcing the database to scan every column even when you only need a subset. The v2 API lets you specify which field groups you need as a comma-separated string:
?fields=core,basic,usageAvailable Field Groups
| Group | Fields |
|---|---|
core | Always included: id, traceId, startTime, endTime, projectId, parentObservationId, type |
basic | name, level, statusMessage, version, environment, bookmarked, public, userId, sessionId |
time | completionStartTime, createdAt, updatedAt |
io | input, output |
metadata | metadata |
model | providedModelName, internalModelId, modelParameters |
usage | usageDetails, inputUsage, outputUsage, totalUsage, costDetails, inputCost, outputCost, totalCost, usagePricingTierName |
prompt | promptId, promptName, promptVersion |
metrics | latency, timeToFirstToken |
trace_context | tags, release, traceName |
If fields is not specified, core and basic field groups are returned by default. Fields from groups you do not request are absent from the response — not null. The following fields are an exception and are always present but only populated when the field group model is selected: modelId, inputPrice, outputPrice, and totalPrice. Note that 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.
2. Cursor-Based Pagination
The v1 API uses offset-based pagination (page numbers) which becomes increasingly slow for large datasets. The v2 API uses cursor-based pagination for better and more consistent performance.
How it works:
- Make your initial request with a
limitparameter - If more results exist, the response includes a
cursorin themetaobject - Pass this cursor via the
cursorparameter in your next request to continue where you left off - Repeat until no cursor is returned (you've reached the end)
Results are always sorted by startTime descending (newest first).
Example response with cursor:
{
"data": [
{"id": "obs-1", "traceId": "trace-1", "name": "llm-call", ...},
{"id": "obs-2", "traceId": "trace-1", "name": "embedding", ...}
],
"meta": {
"cursor": "eyJsYXN0U3RhcnRUaW1lIjoiMjAyNS0xMi0xNVQxMDozMDowMFoiLCJsYXN0SWQiOiJvYnMtMTAwIn0="
}
}When the response has no cursor in meta (or meta.cursor is null), you've retrieved all matching observations.
3. Optimized I/O Handling
The v1 API always attempts to parse input/output as JSON which can be expensive. The v2 API returns I/O as strings by default. Set parseIoAsJson: true only when you need parsed JSON.
4. Stricter Limits
| Feature | v1 | v2 |
|---|---|---|
| Default limit | 1000 | 50 |
| Maximum limit | Unlimited | 1,000 |
Common Use Cases
Polling for recent observations:
curl \
-H "Authorization: Basic <BASIC AUTH HEADER>" \
"https://cloud.langfuse.com/api/public/v2/observations?fromStartTime=2025-12-15T00:00:00Z&toStartTime=2025-12-16T00:00:00Z&limit=10"Getting observations for a specific trace:
curl \
-H "Authorization: Basic <BASIC AUTH HEADER>" \
"https://cloud.langfuse.com/api/public/v2/observations?fields=core,basic,usage&traceId=your-trace-id"Paginating through results:
# First request
curl \
-H "Authorization: Basic <BASIC AUTH HEADER>" \
"https://cloud.langfuse.com/api/public/v2/observations?fromStartTime=2025-12-01T00:00:00Z&limit=100"
# Response includes: "meta": { "cursor": "eyJsYXN0..." }
# Next request with cursor
curl \
-H "Authorization: Basic <BASIC AUTH HEADER>" \
"https://cloud.langfuse.com/api/public/v2/observations?fromStartTime=2025-12-01T00:00:00Z&limit=100&cursor=eyJsYXN0..."Parameters
| Parameter | Type | Description |
|---|---|---|
fields | string | Comma-separated list of field groups to include. Defaults to core,basic |
limit | integer | Number of items per page. Defaults to 50, max 1,000 |
cursor | string | Base64-encoded cursor for pagination (from previous response) |
fromStartTime | datetime | Retrieve observations with startTime on or after this datetime |
toStartTime | datetime | Retrieve observations with startTime before this datetime |
traceId | string | Filter by trace ID |
name | string | Filter by observation name |
type | string | Filter by observation type (GENERATION, SPAN, EVENT) |
userId | string | Filter by user ID |
level | string | Filter by log level (DEBUG, DEFAULT, WARNING, ERROR) |
parentObservationId | string | Filter by parent observation ID |
environment | string | Filter by environment |
version | string | Filter by version tag |
parseIoAsJson | boolean | Parse input/output as JSON (default: false) |
filter | string | JSON array of filter conditions (takes precedence over query params) |
Sample Response
With all fields included
{
"data": [
{
"id": "support-chat-7-950dc53a-gen",
"traceId": "support-chat-7-950dc53a",
"startTime": "2025-12-17T16:09:00.875Z",
"projectId": "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
"parentObservationId": null,
"type": "GENERATION",
"endTime": "2025-12-17T16:09:01.456Z",
"name": "llm-generation",
"level": "DEFAULT",
"statusMessage": "",
"version": "",
"environment": "default",
"bookmarked": false,
"public": false,
"completionStartTime": "2025-12-17T16:09:00.995Z",
"createdAt": "2025-12-17T16:09:00.875Z",
"updatedAt": "2025-12-17T16:09:01.456Z",
"input": "{\"messages\":[{\"role\":\"user\",\"content\":\"Perfect.\"}]}",
"output": "{\"role\":\"assistant\",\"content\":\"You're all set. Have a great day!\"}",
"metadata": {},
"providedModelName": "gpt-4o",
"internalModelId": "clm1a2b3c4d5e6f7g8h9i0j1",
"modelParameters": {
"temperature": 0.2
},
"usageDetails": {
"input": 98,
"output": 68,
"total": 166
},
"inputUsage": 98,
"outputUsage": 68,
"totalUsage": 166,
"costDetails": {
"input": 0.00049,
"output": 0.00204,
"total": 0.00253
},
"inputCost": 0.00049,
"outputCost": 0.00204,
"totalCost": 0.00253,
"promptId": "",
"promptName": "",
"promptVersion": null,
"latency": 0.581,
"timeToFirstToken": 0.12,
"userId": "",
"sessionId": "support-chat-session",
"modelId": "clm1a2b3c4d5e6f7g8h9i0j1",
"inputPrice": "0.000005",
"outputPrice": "0.00003",
"totalPrice": null,
"usagePricingTierName": null,
"tags": ["support", "chat"],
"release": "v1.4.2",
"traceName": "support-chat"
}
],
"meta": {
"cursor": "eyJsYXN0U3RhcnRUaW1lVG8iOiIyMDI1LTEyLTE3VDE2OjA5OjAwLjg3NVoiLCJsYXN0VHJhY2VJZCI6InN1cHBvcnQtY2hhdC03LTk1MGRjNTNhIiwibGFzdElkIjoic3VwcG9ydC1jaGF0LTctOTUwZGM1M2EtZ2VuIn0="
}
}API Reference: See the full v2 Observations API Reference for all available parameters, response schemas, and interactive examples.