Skip to Content
Rius

How do I move my instrumentation code from Langfuse to Rius?

Rius takes OpenTelemetry traces, so moving your Langfuse instrumentation is mostly a routing change. If you send OTLP, you keep your code and re-point the exporter at Rius. If you use the Langfuse SDK, you swap it for the Rius SDK, whose decorators, context managers and session scope have the same shape. Scores, evals, datasets and prompt management have no counterpart in Rius.

How it works

Langfuse and Rius both build on OpenTelemetry, so your traces are already spans. The concepts map like this:

  • Trace, span and generation stay the same. A generation is a span with a model, tokens and cost.
  • Project becomes an agent, named by service.name. Give each environment, such as production and staging, its own workspace and API key.
  • Session stays a session, grouping traces into a conversation or task.
  • User (user_id) becomes user.id. Set it with rius.user(...), or put user.id on every span of the trace, the root included. Each user’s cost, failures and traces appear on the Users page.
  • Scores, prompt management, datasets and evals have no equivalent in Rius.

There are two paths. If your code sends OTLP to Langfuse (OpenLLMetry, OpenInference, a vanilla OpenTelemetry SDK or a Collector), take Path A and change only the exporter settings. Rius reads the OpenTelemetry GenAI conventions, OpenInference conventions and OpenLLMetry attributes, so model, token and cost analytics work without code changes. If your code uses the Langfuse SDK (@observe, start_as_current_observation), take Path B and swap the SDK. The full walkthrough is in Migrate from Langfuse to Rius, and Migrate to Rius covers the other tools.

Rius computes cost from the model and token counts on your spans. You never send a cost value.

Set it up

  1. Create a Rius workspace and an API key. Keys start with ri_.
  2. Path A, keep your instrumentation. Langfuse’s endpoint uses Basic auth built from a public and a secret key. Rius takes one API key as a Bearer token over OTLP/HTTP. Change the exporter settings:
# 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>"

Set OTEL_SERVICE_NAME if your setup does not set a service name, because it names the agent in Rius. Rius takes OTLP over HTTP, not gRPC, so use the otlphttp exporter if you route through a Collector. 3. Path B, swap the SDK. Install the SDK with pip install glassflow-rius and map each call:

  • Langfuse(public_key=..., secret_key=..., base_url=...) or get_client() becomes rius.init(api_key="ri_...", service_name="my-agent").
  • @observe() becomes @rius.observe, and capture_input=False works the same way.
  • @observe(as_type="generation") has no decorator mode. Use rius.start_as_current_generation(...) inside the function.
  • start_as_current_observation(as_type="span", name=...) becomes rius.start_as_current_span(name).
  • span.update(input=..., output=...) becomes span.set_input(...) and span.set_output(...).
  • gen.update(usage_details=...) becomes gen.set_usage(input_tokens=i, output_tokens=o).
  • propagate_attributes(session_id=...) becomes with rius.session(session_id):, and the user_id form becomes with rius.user(user_id):.

A generation in Rius looks like this:

# 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, )
  1. Check the integrations list before porting generation blocks one by one. For OpenAI, Anthropic and other supported libraries, rius.init() instruments the calls and you may not need manual generations. Keep a ported generation only for a call no integration records. If you keep one for a call an integration also records, pass rius.init() an instruments list without that integration, or the call’s tokens and cost are counted twice.
  2. Run both backends side by side. Add Rius as a second exporter in your Collector, or run the swapped SDK in one service while the rest still report to Langfuse.
  3. Verify one traced request: the trace tree looks right, the generation shows model and token counts, and cost appears.
  4. Compare trace counts, token totals and cost on real traffic. Then move anything that reads from Langfuse, remove the Langfuse exporter or SDK, and revoke the Langfuse keys.

What you get

  • Your traces, sessions and users carry over, with token and cost analytics. Cost is a list-price estimate in US dollars.
  • A single RIUS_API_KEY replaces the Langfuse key pair, and the endpoint defaults to EU ingest, so most setups configure nothing else.
  • With the Rius SDK you also see which agent processes are alive, and with partial spans turned on, runs still in progress.
  • The Rius MCP server lets your coding agent query your traces.
  • A reversible migration. Both backends receive the same spans until you cut over.
  • A new organization starts on a 30-day or 500,000-span trial, whichever comes first, with no card.

When something else fits

  • If you rely on scores, annotation queues, LLM-as-judge evals, datasets or versioned prompts, keep Langfuse for those and send your traces to both tools.
  • If you need to self-host, note that Rius is a managed service only.
  • Existing traces stay in Langfuse. Rius starts from the first span you send it.

Still stuck? Get help

Last updated on