How do I migrate from Arize Phoenix to Rius?
Rius reads the OpenInference spans that Phoenix uses, so you keep your instrumentors and change only where they send spans. Re-point register() or your OTLP exporter at Rius, or replace register() with rius.init(), then run both backends side by side and cut over. The full walkthrough is in Migrate from Arize Phoenix, and the general approach is in Migrate to Rius.
How it works
Phoenix is built on OpenTelemetry and OpenInference, so the migration is a routing change, not a re-instrumentation.
What stays
- Your OpenInference instrumentors keep producing the same spans, with the same trace tree.
- Span kinds (
AGENT,LLM,TOOL,CHAIN,RETRIEVER,EMBEDDING,RERANKER) are read as they are. An LLM span becomes a generation with model, token and cost analytics. using_sessionandusing_userkeep working, because they stampsession.idanduser.id, which Rius reads directly.
What changes
- The exporter points at Rius: the endpoint
https://ingest.eu.console.rius-glassflow.com/v1/traces, your Rius API key as a Bearer token, and OTLP over HTTP (protobuf or JSON, not gRPC). - A Phoenix project becomes a Rius agent, named by the
service.nameresource attribute.openinference.project.nameis stored but does not drive grouping. If you used projects to separate environments, give each environment its own workspace and API key. - Cost is computed by Rius from the model and token counts. You send tokens, never cost.
- Metadata and tags are stored as span attributes you can filter by key.
You choose between two paths. Path A keeps register() or your own tracer provider and only re-points the exporter, which is the smallest diff. Path B replaces register() with rius.init(), which wires the same instrumentors and adds heartbeats, privacy controls and session and user scopes.
Set it up
- Create a Rius workspace and an API key. A new organization starts on a trial of 30 days or 500,000 spans, whichever comes first, with no card.
- Re-point the exporter (Path A). Pass the full traces URL, the protocol and the key in code, and set a service name:
import os
from opentelemetry.sdk.resources import Resource
from phoenix.otel import register
tracer_provider = register(
endpoint="https://ingest.eu.console.rius-glassflow.com/v1/traces",
protocol="http/protobuf",
api_key=os.environ["RIUS_API_KEY"],
batch=True,
resource=Resource.create({"service.name": "my-agent"}),
auto_instrument=True,
)- Check three details. Setting only
PHOENIX_COLLECTOR_ENDPOINTto the Rius URL sends spans to the wrong port, so passendpointandprotocolin code. Without aservice.name, traces arrive asunknown_service. Usebatch=Truein production, becauseregister()otherwise exports each span synchronously. - Raise the span attribute limit if you do not use the Rius SDK. OpenTelemetry keeps 128 attributes per span by default, and a long agent loop can lose the model, usage or output on later turns. Set
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=4096. - Set
session.idanduser.idon the root span too.using_sessionandusing_useronly stamp spans created by OpenInference, so a root span from a plain OpenTelemetry tracer shows up as a single-trace session with no user. Start roots from the OpenInference tracer or set the attributes yourself. - Run both backends in parallel. Keep
register()pointed at Phoenix and add Rius as a second span processor withreplace_default_processor=False. Without that flag, the provider drops its Phoenix exporter. If you already use an OpenTelemetry Collector, add one extraotlphttpexporter there instead. - Optionally switch to Path B. Uninstall
arize-phoenix-otel, install the SDK, and replaceregister()andusing_sessionwithrius.init()andrius.session:
import rius
rius.init(service_name="my-agent")
with rius.session(conversation_id):
run_agent(message)Switch using_user to rius.user in the same change, since the OpenInference context managers do not stamp spans you start with rius.start_as_current_span or @rius.observe.
8. Verify one traced request end to end. The trace tree looks right, the LLM span shows as a generation with model and token counts, cost appears, and the trace sits under the session and user you expect. Then compare trace counts, token totals and cost on real traffic for a few days.
9. Cut over. Move anything that reads from Phoenix, remove the Phoenix exporter, and revoke the Phoenix API key once nothing sends to it.
What you get
- The same spans you send Phoenix today, with session and user grouping, server-side cost and alerts.
- Cost per call as a list-price estimate in US dollars. A model Rius does not know stays unpriced, with an empty cost instead of zero.
- An MCP server, so your coding agent can query production traces.
- With the Rius SDK, heartbeats that show which agent processes are alive. With partial spans turned on, you also see runs still in progress.
- A managed service, so there is no Phoenix server or database to run.
- A reversible migration, because the side-by-side setup lets you compare both backends until you remove the Phoenix exporter.
When something else fits
- Rius has no evals, datasets, experiments, prompt management, playground or annotations. If those are central to your workflow, run the side-by-side setup and keep Phoenix for them rather than cutting over completely.
- Rius is a managed service only, prices at public list prices with no custom model prices, and cannot import historical Phoenix traces. Keep Phoenix for the history, since Rius starts from the first span you send.