How to update traces, observations, and scores?
This guide covers how to update traces, observations, and scores in Langfuse, highlighting differences between available update methods.
What can I update?
Langfuse is moving to a mostly immutable data model for observability data (traces and observations in the Langfuse data model).
If you want to enrich traces or observations after they were ingested with evaluations/annotations, please look into scores (docs) that can be added to traces, observations, sessions, and dataset runs at any time.
Updating Traces, Observations, and Scores
Via the Langfuse UI
UI-based updates (tags, bookmarks, publishing) can be made at any time for Traces and Scores.
Via SDK or Ingestion API
- You can upsert traces, observations, and scores based on their
id
(and, optionally,timestamp
for traces,startTime
for observations, andtimestamp
for scores, respectively). - Within 60 days of creation, updates will be merged into the existing trace, observation, or score.
- After 60 days, updates may create duplicate entries containing only the changed fields. This can lead to inconsistencies in dashboards and historical filtering.
- Sending a full event with
id
, sametimestamp/startTime
, and all desired properties will always replace the existing record instead of producing a duplicate and is recommended for long-term updates.
Example behaviour
In the following code block, we run through multiple update cases and their expected results. We will pretend that only the first statement run in the context of each of the updates, i.e. the calls are not considered to be run in order. We will use traces as the example case, but the same applies to observations and scores.
## Create a new trace
{ id: "foo", timestamp: "2025-01-01T12:00:00Z", name: "My Trace" }
-> { id: "foo", timestamp: "2025-01-01T12:00:00Z", name: "My Trace" }
## Send a delta-update within 60 days (e.g. on 2025-02-01). This updates the original trace.
{ id: "foo", userId: "user_1" }
-> { id: "foo", timestamp: "2025-01-01T12:00:00Z", name: "My Trace", userId: "user_1" }
## Send a delta-update after more than 60 days (e.g. on 2025-05-01). This creates a duplicate record.
{ id: "foo", userId: "user_2" }
-> { id: "foo", timestamp: "2025-01-01T12:00:00Z", name: "My Trace" }, { id: "foo", timestamp: "2025-05-01T00:00:00Z", userId: "user_2" }
## Send a delta-update after more than 60 days (e.g. on 2025-05-01) with the original timestamp. This will replace the original record.
{ id: "foo", timestamp: "2025-01-01T12:00:00Z", userId: "user_3" }
-> { id: "foo", timestamp: "2025-01-01T12:00:00Z", userId: "user_3" }
## Send a full replacement after more than 60 days (e.g. on 2025-05-01) with the original timestamp. This will replace the original record.
{ id: "foo", timestamp: "2025-01-01T12:00:00Z", name: "My Trace", userId: "user_4" }
-> { id: "foo", timestamp: "2025-01-01T00:00:00Z", name: "My Trace", userId: "user_4" }