Skip to Content

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 most 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: the same traces you send Langfuse today get session grouping and server-side cost, with an MCP server so your coding agent can query them. With the Rius SDK you also see which agent processes are alive and, with partial spans turned on, runs still in progress. What Langfuse offers beyond tracing is listed in what does not carry over.

Concept mapping: Langfuse vs Rius

LangfuseRiusNotes
TraceTraceSame OpenTelemetry trace, same tree view.
ProjectAgent (named by service.name)Rius groups traces by agent, named by service.name. Give each environment (production, staging) its own workspace and API key.
Observation (span)SpanThe Rius SDK calls it Observation, as Langfuse does.
Observation (generation)GenerationSame idea: a span with LLM semantics (model, tokens, cost).
SessionSessionGroup traces into a conversation or task.
User (user_id)User (user.id)Set it with rius.user(...), or set user.id on every span of the trace, the root included, from your own instrumentation. Each user’s cost, failures and traces appear on the Users page.
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, so the swap is mostly 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. Traces are grouped by agent, named by your service.name; set OTEL_SERVICE_NAME if your setup does not set one. For instrumentation-specific setup, see:

Rius reads both the OpenTelemetry GenAI conventions (gen_ai.*) and the OpenInference conventions (llm.*), as well as OpenLLMetry’s attributes, so model, token and cost analytics work with any of these instrumentations. See the supported conventions for what each convention gets.

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. Use the otlphttp exporter: Rius takes OTLP over HTTP, not gRPC.

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="ri_...", 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(model=..., provider=...); the name is optional and defaults to chat <model>
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=...)with rius.user(user_id):

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 has no equivalent today 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.
  • Datasets: no datasets of test cases or experiment runs against them.
  • Prompt management: no versioned prompts or prompt deployment. Prompt content on spans is captured and inspectable, but there is no registry.
  • Self-hosting: Langfuse can be self-hosted; Rius is a managed service only.
  • Historical data: existing traces stay in Langfuse; Rius starts from the first span you send it.

If scores, evals or prompt management are part of how you work, keep Langfuse for them and send your traces to both tools with the side-by-side setup.

What carries over: traces, sessions, users, token and cost analytics. With the Rius SDK you also see which agent processes are alive and, with partial spans on, runs in progress. The MCP server lets your coding agent query traces.

Langfuse to Rius cutover checklist

  1. Create a Rius workspace and API key (quickstart). New organizations start with a free trial (30 days or 500,000 spans, whichever comes first), then a paid plan; see Plans and billing.
  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 cannot 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 mostly mechanical.

Last updated on