Skip to Content
RiusGuidesMigrate from Langfuse

Migrate from Langfuse to Rius

Langfuse and Rius are both OpenTelemetry-based, which makes migrating from Langfuse mostly a routing change: your traces are already spans, and in many setups Rius can receive them without touching your instrumentation. This guide maps the concepts, walks the two migration paths, and ends with a cutover checklist. Run both backends in parallel during the evaluation; nothing here requires a hard switch.

TL;DR: Migration is a routing change, not a re-instrumentation. Keep your setup and re-point your OTLP exporter (Path A), or swap the Langfuse SDK for the Rius SDK (Path B). Run both in parallel, then cut over.

Why migrate from Langfuse to Rius

Rius is agent observability built for long-running agents, so the same traces you send Langfuse today gain a live view of runs in progress, session grouping, and server-side cost, with an MCP server so your coding agent can query them. What Langfuse offers beyond tracing is covered honestly in what does not carry over.

Concept mapping: Langfuse vs Rius

LangfuseRiusNotes
TraceTraceSame OpenTelemetry trace, same tree view.
Observation (span)SpanThe Rius SDK still names the handle Observation, so the terminology matches Langfuse.
Observation (generation)GenerationSame idea: a span with LLM semantics (model, tokens, cost). Rius reads OTel GenAI gen_ai.* attributes.
SessionSessionGroup traces into a conversation or task.
User (user_id)Span attributeNo native user dimension today. Set user_id as a span attribute; it is stored and inspectable on the trace, but does not drive analytics.
ScoresNot availableSee what does not carry over.
Prompt managementNot availableSee what does not carry over.
Datasets and evalsNot availableSee what does not carry over.

Choose your path

  • You send OTLP to Langfuse (OpenLLMetry, OpenInference, a vanilla OTel SDK, or a Collector pointing at Langfuse’s OTLP endpoint): keep your instrumentation and re-point the exporter.
  • You use the Langfuse SDK (@observe, start_as_current_observation): swap to the Rius SDK. The APIs are close relatives, the swap is mechanical.

Path A: keep your instrumentation (re-point the OTLP exporter)

Langfuse’s OTLP endpoint authenticates with Basic auth built from your public and secret keys. Rius takes a single API key as a Bearer token, and the endpoint is plain OTLP/HTTP:

# Before: pointing at Langfuse export OTEL_EXPORTER_OTLP_ENDPOINT="https://cloud.langfuse.com/api/public/otel" export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <base64 public:secret>" # After: pointing at Rius export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.eu.console.rius-glassflow.com" export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer <your API key>"

That is the whole change. Instrumentation-specific setup lives on the existing pages, use the one that matches yours:

What analytics you get depends on the attribute convention your instrumentation emits; check the supported-conventions matrix. Recent OpenLLMetry and OpenInference releases emit gen_ai.* attributes and get full model and cost analytics.

Side by side through a Collector

For an evaluation period, keep sending to Langfuse and add Rius as a second exporter. If you already route through an OpenTelemetry Collector this is one list entry:

exporters: otlphttp/langfuse: endpoint: https://cloud.langfuse.com/api/public/otel headers: authorization: Basic ${env:LANGFUSE_BASIC_AUTH} otlphttp/rius: endpoint: https://ingest.eu.console.rius-glassflow.com encoding: proto compression: gzip headers: authorization: Bearer ${env:RIUS_API_KEY} service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [otlphttp/langfuse, otlphttp/rius]

Both backends now see identical spans, so you can compare trace trees, token counts, and cost on the same traffic before deciding. The Collector page covers the exporter details, including why it must be otlphttp and not otlp.

No Collector in your stack? Adding one just for the evaluation is a small, reversible step: run it as a sidecar or single deployment, point your app’s OTLP exporter at it, and fan out from there. Remove it after cutover or keep it as your single egress point.

Path B: swap the Langfuse SDK for the Rius SDK

For code instrumented with the Langfuse SDK, the Rius SDK (Python and TypeScript) has the same shape: a decorator for functions, context managers for spans and generations, and a session scope.

Langfuse (Python)Rius (Python)
Langfuse(public_key=..., secret_key=..., base_url=...) / get_client()rius.init(api_key="gf_...", service_name="my-agent")
@observe()@rius.observe
@observe(capture_input=False)@rius.observe(capture_input=False)
@observe(as_type="generation")Use rius.start_as_current_generation(...) inside the function; the decorator has no generation mode.
start_as_current_observation(as_type="span", name=...)rius.start_as_current_span(name)
start_as_current_observation(as_type="generation", model=...)rius.start_as_current_generation(name, model=..., provider=...)
span.update(input=..., output=...)span.set_input(...) / span.set_output(...)
gen.update(usage_details={"input_tokens": i, "output_tokens": o})gen.set_usage(input_tokens=i, output_tokens=o)
propagate_attributes(session_id=...)with rius.session(session_id):
propagate_attributes(user_id=...)span.set_attribute("user_id", user_id) on the spans that need it; carried on the trace, not a native dimension.

A generation, before and after:

# Langfuse with langfuse.start_as_current_observation( as_type="generation", name="chat gpt-4o", model="gpt-4o", ) as gen: response = client.chat.completions.create(model="gpt-4o", messages=messages) gen.update( output=response.choices[0].message.content, usage_details={ "input_tokens": response.usage.prompt_tokens, "output_tokens": response.usage.completion_tokens, }, )
# Rius with rius.start_as_current_generation( "chat gpt-4o", model="gpt-4o", provider="openai", ) as gen: gen.set_input(messages) response = client.chat.completions.create(model="gpt-4o", messages=messages) gen.set_output(response.choices[0].message.content) gen.set_usage( input_tokens=response.usage.prompt_tokens, output_tokens=response.usage.completion_tokens, )

Two differences worth knowing before you start:

  • Auth and config: one RIUS_API_KEY replaces the Langfuse key pair, and the endpoint defaults to EU ingest so most setups configure nothing else. See installation.
  • Instrumentation is automatic where possible: if you call OpenAI, Anthropic, or another supported library, rius.init() instruments it and you may not need manual generations at all. Check the integrations list before porting generation blocks one by one.

The full API surface, including manual (non-context-manager) span control, is in the tracing guide and the SDK reference.

What does not carry over from Langfuse

Rius is an agent observability platform, not a Langfuse clone, and today it has no equivalent for:

  • Scores: no score objects on traces or observations, and no annotation queues.
  • Evals: no LLM-as-judge or eval runs. If you run evals through Langfuse today, keep that workflow there or in a dedicated eval tool during the transition.
  • Prompt management: no versioned prompts or prompt deployment. Prompt content on spans is captured and inspectable, but there is no registry.
  • User-level analytics: no native user_id dimension. A user_id span attribute is carried over and visible in trace inspection, but there are no per-user views or rollups.

What you keep, and in some places gain: trace inspection, sessions, token and server-side cost analytics, a live view of running agents including long-running ones, and an MCP server so your coding agent can query production traces.

If scores, evals, or prompt management are load-bearing in your workflow, run the side-by-side setup and keep Langfuse for those pieces rather than cutting over completely. Traces are cheap to duplicate; workflows are not.

Langfuse to Rius cutover checklist

  1. Create a Rius workspace and API key (quickstart).
  2. Pick your path: re-point OTLP or swap the SDK.
  3. Start with fan-out, not a switch: send the same traces to both backends (Collector fan-out), or run the swapped SDK in one service while the rest still report to Langfuse.
  4. Verify one traced request end to end: the trace tree looks right, the generation shows model and token counts, and cost appears. If analytics fields are empty, check your attribute convention against the matrix.
  5. Compare both backends on real traffic for a few days: trace counts, token totals, cost.
  6. Move anything that reads from Langfuse (dashboards, alerts, internal tools) to their Rius equivalents, or deliberately leave them behind.
  7. Remove the Langfuse exporter or SDK, and revoke the Langfuse keys once nothing sends to them.

Frequently asked questions

Do I have to re-instrument my code to migrate from Langfuse?

No. Because both are OpenTelemetry-based, in most setups you re-point your OTLP exporter to Rius and your existing spans arrive unchanged.

Can I run Langfuse and Rius at the same time?

Yes. Add Rius as a second exporter and fan out to both during evaluation. The migration is reversible until you revoke your Langfuse keys.

Is Rius compatible with the Langfuse SDK?

Not directly. You can’t point the Langfuse SDK at Rius, because its exporter and auth are Langfuse’s own. The Rius SDK mirrors the Langfuse SDK’s shape (decorators, context managers, sessions), so swapping one for the other is rather mechanical.

Last updated on