---
title: Migrate from Arize Phoenix to Langfuse
description: "Step-by-step guide to migrating from Arize Phoenix to Langfuse: keep OpenInference instrumentation, replace phoenix.otel.register(), and recreate datasets, prompts, and experiments."
tags: [migration, guide]
---

# Migrate from Arize Phoenix to Langfuse

This guide walks through migrating LLM observability from
[Arize Phoenix](https://phoenix.arize.com) to [Langfuse](/): tracing first (usually a
same-day change), then datasets, experiments, and prompts.

Dynatrace [announced a definitive agreement to acquire Arize](https://www.dynatrace.com/news/press-release/dynatrace-to-acquire-arize/) (August 2026).
Arize AX and Phoenix continue to operate as they do today. This guide is for teams that have
already decided to move to Langfuse from **Phoenix**. If you are on Arize AX (spaces,
`arize.otel.register()`), use [Migrate from Arize AX](/resources/engineering/migrate-from-arize-ax). For a product comparison, see
[Langfuse vs. Arize AX / Phoenix](/resources/engineering/best-phoenix-arize-alternatives).

**TL;DR:** Keep your OpenInference instrumentors. Replace `phoenix.otel.register()` with the
Langfuse client, then call `.instrument()` on the same OpenInference package. Datasets, prompts, and evaluators are
recreated via the Langfuse SDK/API; experiments re-run against the migrated datasets.

Want help cutting over? [Talk to us](/talk-to-us) about Cloud (EU, US, Japan; [HIPAA](/security/hipaa) on Pro+) or self-host. Core features match Cloud; enterprise governance modules need an [Enterprise license](/pricing-self-host) when self-hosted.

- [Get started free](https://cloud.langfuse.com)
- [Talk to us](/talk-to-us)

## Why teams migrate

Teams tend to evaluate a Phoenix-to-Langfuse move for a few recurring reasons:

- **Hosting and licensing model.** Phoenix is source-available under the Elastic License 2.0
  (as of August 2026). It is free to self-host on SQLite or PostgreSQL. Arize AX is a
  separate proprietary product; self-hosting AX is an Enterprise option. Langfuse's core is
  MIT-licensed, and [self-hosting](/self-hosting) runs the same core product as
  [Langfuse Cloud](https://cloud.langfuse.com) (EU, US, Japan; [HIPAA](/security/hipaa) on Pro+ with a signed BAA). Enterprise
  governance modules need an [Enterprise license](/pricing-self-host) when self-hosted.
- **Organizations and tenancy.** A Phoenix instance is one tenant: projects live inside it,
  with instance-wide [admin / member / viewer](https://arize.com/docs/phoenix/settings/access-control-rbac)
  roles and OAuth2/LDAP. Langfuse adds [organizations](/docs/administration/rbac) above
  projects, plus project-level RBAC and [Enterprise SSO](/docs/administration/authentication-and-sso). Phoenix documents org/space multi-tenancy and SAML as
  [Arize AX](https://arize.com/docs/ax/security-and-settings/sso-and-rbac) features.
- **One product for the production loop.** Phoenix covers tracing, evals, datasets,
  experiments, and prompts as a local-first app. Continuous evals on production traffic with
  alerting are an [Arize AX](https://arize.com/docs/ax/evaluate/online-evals) feature.
  Langfuse keeps that loop on one MIT codebase: production traces feed
  [datasets](/docs/evaluation/experiments/datasets) and
  [experiments](/docs/evaluation/experiments/experiments-via-sdk),
  [managed evaluators](/docs/evaluation/overview) can run on live traffic, and
  [custom dashboards](/docs/metrics/features/custom-dashboards) sit on the same data model.

Phoenix remains a capable tool for local, notebook, and self-hosted workflows, and if it
serves your team well, there is no urgency to move. This guide is for teams that have decided
to consolidate on Langfuse.

## Concept mapping

Phoenix and Langfuse share most concepts, which keeps the mental migration small:

| Phoenix                        | Langfuse                                                                                                                                                   | Notes                                                                            |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Project                        | Project                                                                                                                                                    | Langfuse project is selected by API keys, not Phoenix `project_name`             |
| Traces / spans (OpenInference) | [Traces / observations](/docs/observability/data-model)                                                                                                    | Same OTel foundation; spans map to observations                                  |
| Datasets                       | [Datasets](/docs/evaluation/experiments/datasets)                                                                                                          | Versioned example collections in both                                            |
| Experiments                    | [Experiments / dataset runs](/docs/evaluation/experiments/experiments-via-sdk)                                                                             | Runs linked to dataset items and scores                                          |
| Evals (LLM and code)           | [Evaluators / LLM-as-a-judge](/docs/evaluation/evaluation-methods/llm-as-a-judge) + [code evaluators](/docs/evaluation/evaluation-methods/code-evaluators) | Both can score experiments and traces. AX productizes online evals with alerting |
| Playground                     | [Playground](/docs/prompt-management/features/playground)                                                                                                  | Replay and iterate on traced calls                                               |
| Prompt Management              | [Prompt Management](/docs/prompt-management)                                                                                                               | Phoenix tags map to Langfuse labels                                              |

## Step 1: Keep OpenInference, replace `register()` [#switch-exporter]

Phoenix apps typically send traces with `phoenix.otel.register()`. Keep your OpenInference
instrumentor (`pip install langfuse`). Replace `register()` with the Langfuse client, then
call `.instrument()` on the same package. Application LLM calls stay unchanged.

```python
# Before
from phoenix.otel import register

register(project_name="my-llm-app", auto_instrument=True)

# After: your existing OpenInference instrumentor (OpenAI shown)
from langfuse import get_client
from openinference.instrumentation.openai import OpenAIInstrumentor  # or AnthropicInstrumentor, LangChainInstrumentor, ...

get_client()
OpenAIInstrumentor().instrument()
```

Set `LANGFUSE_PUBLIC_KEY`, `LANGFUSE_SECRET_KEY`, and `LANGFUSE_BASE_URL`
(`https://cloud.langfuse.com` for EU; see [Get started](/docs/observability/get-started) for
US, Japan, HIPAA, and self-hosted). Confirm LLM spans show as generations with input, output,
and token/cost.

Worked example: [Tracing using the OpenInference SDK](/integrations/other/openinference).

<Details>
<Summary>Phoenix tracing notes</Summary>

Do not rely on a naive OTEL env-var swap while still calling `register()`. That helper prefers
`PHOENIX_COLLECTOR_ENDPOINT`, Bearer auth, and on Python defaults toward gRPC. Langfuse
accepts [OTLP over HTTP](/integrations/native/opentelemetry) with Basic auth.

In the **application** process, unset `PHOENIX_COLLECTOR_ENDPOINT` and `PHOENIX_API_KEY`, and
check for a `.env.phoenix` file (Phoenix SDKs auto-load it). Restart after the change. Langfuse
routes traces by API key, not Phoenix `project_name`. Call `get_client()` **before**
`.instrument()`. In scripts and notebooks, call `langfuse.flush()` before exit.

If you already export with a generic `OTLPSpanExporter` or a collector (not `register()`),
point that exporter at Langfuse:

```bash
OTEL_EXPORTER_OTLP_ENDPOINT="https://cloud.langfuse.com/api/public/otel"  # EU
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic ${AUTH_STRING},x-langfuse-ingestion-version=4"
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
```

`AUTH_STRING` is `echo -n "pk-lf-...:sk-lf-..." | base64`. The traces path is
`/api/public/otel/v1/traces` when the exporter needs a signal-specific URL.

Langfuse maps OpenTelemetry `user.id` / `session.id` (and `langfuse.user.id` /
`langfuse.session.id`) when those attributes are set. HIPAA Cloud
(`https://hipaa.cloud.langfuse.com`) is on Pro+ and needs a signed BAA before sending PHI.

If Phoenix showed an agent loop and tools around the LLM call, and Langfuse only shows the
LLM call, [Python SDK v4](/docs/observability/sdk/upgrade-path/python-v3-to-v4) is filtering
those extra spans.

</Details>

## Step 2: Migrate datasets

Export dataset examples with the Phoenix client and recreate them with the Langfuse SDK. The
shapes are close: each example's input, expected output, and metadata map directly.

```python
from phoenix.client import Client as PhoenixClient
from langfuse import get_client

phoenix = PhoenixClient(base_url="http://localhost:6006")  # your Phoenix URL
source = phoenix.datasets.get_dataset(dataset="my-dataset")

langfuse = get_client()
langfuse.create_dataset(name="my-dataset")  # skip if the dataset already exists

for example in source:
    langfuse.create_dataset_item(
        id=example["id"],
        dataset_name="my-dataset",
        input=example["input"],
        expected_output=example["output"],
        metadata=example.get("metadata") or {},
    )
```

<Details>
<Summary>Dataset import notes</Summary>

This copies the latest snapshot, not the full version history. Pass `base_url` so the Phoenix
client does not need `PHOENIX_COLLECTOR_ENDPOINT`. Authenticated Phoenix instances still need
`PHOENIX_API_KEY` (or `api_key=`) in this export process only.

A stable `id` (the Phoenix example id) makes a retry safe. Extra fields (tags, split labels,
provenance) belong in `metadata`. Confirm item counts match after import.

</Details>

## Step 3: Recreate prompts and evaluators

Copy Phoenix chat messages into a Langfuse `type="chat"` prompt. Phoenix tags map to Langfuse
labels (for example `production`).

```python
langfuse.create_prompt(
    name="my-prompt",
    type="chat",
    prompt=[{"role": "user", "content": "Answer in one sentence: {{question}}"}],
    labels=["production"],
)
prompt = langfuse.get_prompt("my-prompt", label="production", type="chat")
prompt.compile(question="Why is the ocean salty?")
```

- **Evaluators:** recreate LLM evals as [managed or custom LLM-as-a-judge
  evaluators](/docs/evaluation/evaluation-methods/llm-as-a-judge), or as
  [code evaluators](/docs/evaluation/evaluation-methods/code-evaluators) where they were
  Python functions. Evaluators in Langfuse can target production traces continuously (online
  evaluation) in addition to experiment runs.
- **Experiments:** re-run against the migrated datasets via the
  [experiments SDK](/docs/evaluation/experiments/experiments-via-sdk) or from the UI.

```python
dataset = langfuse.get_dataset("my-dataset")

def task(*, item, **kwargs):
    messages = prompt.compile(**item.input)
    return run_your_app(messages)  # same path as production

dataset.run_experiment(name="after-migration", task=task)
```

<Details>
<Summary>Prompt template notes</Summary>

Use `type="text"` only for a single string. Convert F-string placeholders (`{question}`) to
Langfuse variables (`{{question}}`). Simple Mustache variables already match; sections and
conditionals are not handled by Langfuse `compile()`. Put model, tools, and response-format
settings in prompt `config` if your app will read them; saving config does not apply them
automatically. Unresolved `{{variables}}` are left as-is. Do not import historical Phoenix
experiment scores.

</Details>

## Step 4: Decide what to do with historical traces

Most teams cut over fresh: old traces stay queryable in Phoenix, and Langfuse becomes the
system of record from cutover day. Bulk-importing historical traces is rarely worth it beyond
a few showcase traces.

<Details>
<Summary>If you need a few historical traces</Summary>

There is no turn-key history import. Re-run those requests, or send OpenTelemetry via the
[OTLP endpoint](/integrations/native/opentelemetry) with `x-langfuse-ingestion-version=4`. Do
not use the deprecated ingestion API.

</Details>

## Validation checklist

- [ ] `phoenix.otel.register()` is gone; traces arrive as generations with token/cost data
- [ ] User and session attribution works if you set `user.id` / `session.id`
- [ ] Datasets migrated with item counts matching the source
- [ ] Prompts resolve by name+label from application code
- [ ] An experiment run exists on the migrated dataset
- [ ] Team access set up (org/project roles, SSO if applicable)
- [ ] Old exporter removed (or parallel window scheduled to end)

## FAQ

### Do I have to re-instrument my application?

No. Keep OpenInference. Replace `phoenix.otel.register()` with
[Langfuse `get_client()`](/docs/observability/sdk/overview) and the same instrumentor's
`.instrument()` call. Re-instrumenting with the Langfuse SDKs later is optional.

### Does Langfuse support the frameworks Phoenix instrumented?

Langfuse has [native integrations](/integrations) for the major frameworks (LangChain,
LlamaIndex, OpenAI, Vercel AI SDK, and more) and accepts OpenInference instrumentation
via OTLP, so framework coverage carries over rather than resetting. See the
[OpenInference cookbook](/integrations/other/openinference).

### Is Langfuse open source where Phoenix is?

Langfuse's core platform is MIT-licensed and self-hostable. Core features match Cloud; enterprise governance modules need an [Enterprise license](/pricing-self-host) when self-hosted.
Phoenix is licensed under the Elastic License 2.0 (source-available) as of August 2026. Check
both licenses against your compliance requirements: ELv2 restricts offering the software as
a managed service, which matters to some platform teams.

### Can I evaluate old Phoenix traces in Langfuse?

Evaluators run on data in Langfuse, so historical evaluation requires those traces to exist
in Langfuse first (see Step 4). The pragmatic path: start evaluators on new traffic at
cutover and backfill only if a specific analysis demands it.

<Details>
<Summary>No traces, generic spans, or duplicate dataset items?</Summary>

- **No traces:** confirm keys and `LANGFUSE_BASE_URL` were set before `get_client()`, the
  instrumentor ran before application calls, `.env.phoenix` is unset in the app process, and
  short-lived processes call `flush()`.
- **Generic spans:** check that OpenInference is actually instrumenting the library you call.
  LLM spans should carry `input.value` / `output.value` and model attributes.
- **Duplicate dataset items:** pass a stable `id` (the Phoenix example id works) on
  `create_dataset_item()`.

</Details>

## Get help with the migration [#get-help]

Start on [Langfuse Cloud](https://cloud.langfuse.com) or [self-host](/self-hosting). If you
want a migration plan, [talk to us](/talk-to-us).

- [Get started free](https://cloud.langfuse.com)
- [Talk to us](/talk-to-us)

<!-- agent-instructions -->

---

## Agent Instructions

This page is part of the [Langfuse](https://langfuse.com) documentation, published as plain Markdown for AI agents. Every page is available as Markdown by appending `.md` to its URL, or by sending an `Accept: text/markdown` header. This page: `https://langfuse.com/resources/engineering/migrate-from-phoenix.md`.

### Querying these docs

If the answer is not on this page, query the documentation instead of guessing:

- **Semantic search** across all Langfuse docs, returning an answer with the relevant pages and excerpts. Ask a specific, self-contained question:

  ```bash
  curl -sG "https://langfuse.com/api/search-docs" --data-urlencode "query=How do I trace a LangGraph agent?"
  ```

- **Index of every page**: <https://langfuse.com/llms.txt>, with per-section indexes [llms-docs.txt](https://langfuse.com/llms-docs.txt), [llms-integrations.txt](https://langfuse.com/llms-integrations.txt), and [llms-self-hosting.txt](https://langfuse.com/llms-self-hosting.txt).

### Before writing Langfuse code

- **Install the [Langfuse Agent Skill](https://langfuse.com/docs/api-and-data-platform/features/agent-skill).** It encodes Langfuse's own best practices for instrumentation, prompt management, and evaluation, and materially improves results.
- **Read [What does a good trace look like?](https://langfuse.com/docs/observability/best-practices.md)** before instrumenting an application.
- **Verify endpoints, parameters, and response fields** against the [API reference](https://api.reference.langfuse.com) instead of inferring them from code examples.
- **Use the [Langfuse CLI](https://langfuse.com/docs/api-and-data-platform/features/cli)** (`npx langfuse-cli api <resource> <action>`) to read or write traces, prompts, datasets, and scores from the terminal.

Found an error in these docs? Please open an issue at <https://github.com/langfuse/langfuse-docs/issues>.
