How do I move my user ids from Arize Phoenix to Rius?
Rius reads the same user.id attribute that Arize Phoenix uses, so your user ids move over by sending your spans to Rius, with no renaming or mapping table. If you keep Phoenix’s using_user, check that the root span of each trace also carries the id. If you switch to the Rius SDK, rius.user replaces using_user and stamps every span in its scope. Ids on traces already stored in Phoenix stay there.
How it works
Phoenix and Rius share one convention for users, so the id itself needs no translation.
- Phoenix:
using_user(user_id)fromopeninference-instrumentationstampsuser.idon the spans it creates. - Rius: the same
user.idattribute feeds the Users page, which lists each end user your agents served with their traces, failures, cost and time to first token. - Root span: the trace list shows a trace under the user of its root span, the top-level span, usually your request handler.
using_useronly stamps spans created by OpenInference: the instrumentors and the tracer from the providerregister()returns. A root span started from a plain OpenTelemetry tracer misses it, and the trace shows no user even though the model call inside carries the right id. - No user id: a span with no
user.idcounts as anonymous. - Metadata and tags: Phoenix’s
using_metadataandusing_tagsbecome ordinary span attributes in Rius. You can filter on them by key, but they get no dedicated view, so they do not stand in for a user id.
The SDK path differs in one way. rius.user stamps every span in its scope, the root and the instrumentors’ spans included, so the root span gap does not arise.
Set it up
-
Re-point your exporter. Keep your OpenInference instrumentors and send spans to Rius, or send to both backends while you compare. The Migrate from Arize Phoenix guide has the exporter code for both setups and the side by side variant. Your
using_usercalls need no edit on this path. -
Put the id on the root span. If your root span comes from a plain OpenTelemetry tracer, set the attributes on it yourself, or start it from the OpenInference tracer:
with tracer.start_as_current_span(
"handle-turn",
attributes={"session.id": conversation_id, "user.id": user_id},
):
run_agent(message)- Or switch to the Rius SDK. Replace
register()withrius.init()andusing_userwithrius.user. Do the same forusing_sessionandrius.sessionin the same change, because the OpenInference context managers do not stamp spans you start withrius.start_as_current_spanor@rius.observe.
pip uninstall arize-phoenix-otel
pip install "glassflow-rius[openai]"
export RIUS_API_KEY="<your API key>"# Before
from phoenix.otel import register
from openinference.instrumentation import using_user
register(project_name="my-agent", auto_instrument=True)
with using_user(user_id):
run_agent(message)# After
import rius
rius.init(service_name="my-agent")
with rius.user(user_id):
run_agent(message)-
Choose what you send as the id. Prefer an opaque id, such as your own database key, to an email address. Rius has no environment variable for users, by design, so set the id in code on each request. In TypeScript the scope is
withUser. -
Verify. Send one traced request and open the Users page. Your user should appear with that trace. If it shows as anonymous, the root span is missing
user.id. The Migrate to Rius page lists the other migration guides if your setup also includes another tool.
What you get
- Your existing
user.idvalues keep their meaning, so a user is the same user before and after the move. - A Users page with each end user’s traces, failures, cost and time to first token. Cost is a list-price estimate in US dollars that Rius computes from model and token counts, and you never send it.
- Session and user grouping that works together: set
session.idanduser.idon every span, the root included, and each trace sits under the right session and user. - With the Rius SDK, one scope per id that covers the root and instrumentor spans alike.
Two things have no counterpart. Phoenix annotations and feedback are not available in Rius, so labels you attached to a user’s spans do not carry over. And there is no import of historical Phoenix data: Rius starts from the first span you send, so older user history stays in Phoenix.
When something else fits
- If you rely on annotations, feedback or evals tied to specific users, keep Phoenix for those workflows and run both backends side by side rather than cutting over completely.
- If you need user history from before the move, keep your Phoenix instance or an export of it, because Rius does not import past traces.