Configure Langfuse
Use your Catalyst API key as the Langfuse secret key. The public key is only present for Langfuse SDK compatibility and its value is never used. Set it topk-catalyst, but any non-empty value works.
Python
Python
TypeScript
TypeScript
Send to Both Langfuse and Catalyst
The setup above points the Langfuse SDK entirely at Catalyst, so all of that SDK’s traffic comes to us. If you want to keep your existing Langfuse pipeline and mirror the same traces into Catalyst, you can fan out to both at once. This is the lowest-risk way to evaluate Catalyst: Langfuse keeps working untouched while Catalyst receives a copy of everything.TypeScript: add a second span processor
The Langfuse JS/TS SDK is OpenTelemetry-based, and OpenTelemetry broadcasts every span to every registered span processor by default. Keep your existingLangfuseSpanProcessor pointed at Langfuse and add a second one pointed at
Catalyst. Your observe calls and the rest of your tracing code do not change.
instrumentation.ts
Python: fan out with an OpenTelemetry Collector
The Python SDK does not broadcast across destinations. Its multi-client mode routes each span to a single project based on a public-key attribute, so it is not a true dual-send: you have to threadlangfuse_public_key through every
@observe, OpenAI wrapper, and Langchain handler call to pick the destination,
and spans without that attribute land everywhere by accident. It is fragile and
not the documented path for sending to both.
The clean, SDK-agnostic way to dual-send from Python (or any runtime) is an
OpenTelemetry Collector with two OTLP exporters. Both Langfuse and Catalyst
accept OTLP, so point your app at a local collector and let the collector ship
to both. Your application code does not change.
otel-collector.yaml
The collector approach works for any OTLP trace source, not just Langfuse. If
you already export OpenTelemetry traces, add a second OTLP exporter for
Catalyst and you are done.
What Maps Into Catalyst
This is v1 of the Langfuse integration — scores, evaluations, and richer
mapping are coming later. Langfuse scores and evaluations are not supported at
this time. Pointing
LANGFUSE_HOST at Catalyst routes all of that SDK’s traffic to us. To keep
sending to Langfuse as well, see Send to both Langfuse and
Catalyst. Scores emitted through the
SDK are not ingested at this point in time.Group by agent
Pointing the base URL at Catalyst sends your spans — but Catalyst does not treat every trace as an agent. A trace name, or even a Langfuseagent-type
observation, is not enough on its own; otherwise every traced workload would
flood the Agents dashboard. Agent grouping is opt-in: set agent.name (and
optionally a stable agent.id) on the top-level span of your agent, and
Catalyst groups that whole trace — and every child span — under it in the
Agents dashboard. This is also what makes the trace available to
Halo, which operates on agents.
The Langfuse SDKs are OpenTelemetry-based and forward raw OTel attributes
untouched, so set the two attributes directly on the active span. Do this
only on the top-level agent span — children inherit grouping through the
trace and should not carry their own agent identity.
agent.name— the human-readable label the Agents dashboard groups on.agent.id— a stable identifier that survives display-name changes. When set, it wins overagent.name, so renaming the agent doesn’t split its history. Omit it if you don’t need stable grouping.
TypeScript
Python
View and Analyze
Once traces arrive, open the Catalyst dashboard and use the Traces tab to inspect individual trace trees. Traces whose top-level span carries anagent.name / agent.id (see Group by agent) are grouped
in the Agents dashboard, where Halo can run analysis over them.
For the best Halo reports, keep agent.id (or agent.name) stable per agent or
workflow and set userId / sessionId when available.