@opentelemetry/api. Your app sets up the tracer provider and exporter, so you can send traces to
Langfuse or any other OpenTelemetry
backend.
Cloud sessions currently report turns and tool calls but not per-request token usage or cost, so
their traces have no
generation spans. Local sessions report both.Install
@opentelemetry/api is an optional peer dependency of the SDK. For Langfuse, also install the
OpenTelemetry trace SDK and Langfuse’s span processor:
Trace every session
Passtracing: traceSessions(...) when you create the client. createDevin,
LocalDevin.start, LocalDevin.connect and CloudDevin.connect all accept it.
- Every session the client opens:
createSession,loadSession,attachandlaunchSession. - Every prompt:
send,run,stream,streamUpdatesandpostMessage, including images and other content blocks. The prompt is recorded as the turn’s input. - Cloud messages from other clients: a message sent from the Devin web app, Slack or another SDK process is traced as its own turn. Your own prompts are not counted twice.
- Attach and reload: history replayed by
loadSessionorattachis not exported again. A turn that is already running when you attach is traced from then on.
tracing option refines the client’s: metadata is merged, tags are added, and
name, userId and sessionId replace the client’s values. Pass tracing: false to leave one
session untraced.
If your app already registers a global provider (for example with @opentelemetry/sdk-node),
leave out tracer and spans use the global provider. Pass parent to nest turns under an
existing span, such as your harness’s own request span. Set recordContent: false to keep
timing, token usage, cost, model and tool names but leave out prompt, reply and tool text.
Trace one session
traceSession traces a single session you already hold, without a client-level option. It only
sees the session’s incoming events, so record each prompt yourself before you send it:
traceSessions.
What a trace contains
Each turn is its own trace unless it has a parent span. Langfuse groups the turns by session id, which defaults to the Devin session’s id, so a session reloaded in a new process shows up in the same Langfuse session.
The last generation of a turn also carries the turn’s request id, time to first token, and ACU
cost when the agent reports it. Set
usdPerAcu to also record that cost in dollars. Spans also
set gen_ai.* attributes for backends other than Langfuse.
Turns that stop on error, quota_exhausted, auth_required or content_filter are marked as
errors. A provider refusal ends the turn with content_filter and keeps any partial output; the
session can take the next prompt. Failed tool calls are errors, and rejected or cancelled ones
are warnings.
Running it in production
- The process running the session needs the Langfuse endpoint, the public and secret keys, and network access to Langfuse.
- Batching, retries and export errors are handled by your span processor. A Langfuse outage never throws into the session.
- If the session’s event stream fails, the open turn is marked
stream_error, and the session reports the failure to your code as it normally would. - Cost fields are only set when the agent reports them. If they are empty, compute cost from the token counts.

