Skip to main content

Arize Phoenix logo
arize-phoenix-client

PyPI Version Documentation

Phoenix Client provides an interface for interacting with the Phoenix platform via its REST API, enabling you to manage datasets, run experiments, analyze traces, and collect feedback programmatically.

Features

  • REST API Interface - Interact with Phoenix's OpenAPI REST interface
  • Prompts - Create, version, and invoke prompt templates
  • Datasets - Create and append to datasets from DataFrames, CSV files, or dictionaries
  • Experiments - Run evaluations and track experiment results
  • Eval CI (pytest) - Run LLM evals as ordinary pytest tests and record them as Phoenix experiments (pip install "arize-phoenix-client[pytest]")
  • Spans - Query and analyze traces with powerful filtering
  • Annotations - Add human feedback and automated evaluations
  • Evaluation Helpers - Extract span data in formats optimized for RAG evaluation workflows

Installation

Install the Phoenix Client with pip:

pip install arize-phoenix-client

Getting Started

Environment Variables

Configure the Phoenix Client using environment variables for seamless use across different environments:

# For local Phoenix server (default)
export PHOENIX_ENDPOINT="http://localhost:6006"

# A hosted or self-hosted instance with authentication
export PHOENIX_ENDPOINT="https://phoenix.example.com"
export PHOENIX_API_KEY="your-api-key"

# Customize headers
export PHOENIX_CLIENT_HEADERS="Authorization=Bearer your-api-key,custom-header=value"

PHOENIX_ENDPOINT is a base URL and is the canonical setting for the client. If your app also exports traces, set PHOENIX_COLLECTOR_ENDPOINT for the OTel SDK — usually to the same value. When only PHOENIX_COLLECTOR_ENDPOINT is set, the client infers its base URL from it. See Environment Variables for the full list.

Credential File Discovery (.env.phoenix)

When a setting is not provided by argument or environment variable, the client looks for a .env.phoenix file in the current working directory — walking up toward the filesystem root and stopping at the first match — and reads PHOENIX_-prefixed keys from it (dotenv format):

# .env.phoenix
PHOENIX_ENDPOINT=http://localhost:6006
PHOENIX_API_KEY=your-api-key

Explicit arguments and environment variables always take precedence — the file never overrides anything already set. Set PHOENIX_DISCOVER_CONFIG=false to disable discovery entirely.

Credentials (PHOENIX_API_KEY and PHOENIX_CLIENT_HEADERS) and server location (PHOENIX_ENDPOINT and the variables it falls back to) are each resolved as a group from one source tier. If explicit or process credentials are paired with an endpoint from .env.phoenix, the client warns once and continues without logging credential values.

Discovery results, including a missing file, are cached per working directory for the process lifetime. Long-running processes can call phoenix.client.utils.config.clear_env_file_cache() after creating or changing the file.

Client Initialization

The client automatically reads environment variables, or you can override them:

from phoenix.client import Client, AsyncClient

# Automatic configuration from environment variables
client = Client()

client = Client(base_url="http://localhost:6006")  # Local Phoenix server

# Remote instance with API key
client = Client(base_url="https://your-phoenix-instance.com", api_key="your-api-key")

# Custom authentication headers
client = Client(
    base_url="https://your-phoenix-instance.com", headers={"Authorization": "Bearer your-api-key"}
)

# Asynchronous client (same configuration options)
async_client = AsyncClient()
async_client = AsyncClient(base_url="http://localhost:6006")
async_client = AsyncClient(base_url="https://your-phoenix-instance.com", api_key="your-api-key")

Resources

The Phoenix Client organizes functionality into resources that correspond to key Phoenix platform features. Each resource provides specialized methods for managing different types of data:

Prompts

Manage prompt templates and versions:

from phoenix.client import Client
from phoenix.client.types import PromptVersion

client = Client()

content = """
You're an expert educator in {{ topic }}. Summarize the following article
in a few concise bullet points that are easy for beginners to understand.

{{ article }}
"""

prompt = client.prompts.create(
    name="article-bullet-summarizer",
    version=PromptVersion(
        messages=[{"role": "user", "content": content}],
        model_name="gpt-4o-mini",
    ),
    prompt_description="Summarize an article in a few bullet points",
)

# Retrieve and use prompts
prompt = client.prompts.get(prompt_identifier="article-bullet-summarizer")

# Format the prompt with variables
prompt_vars = {
    "topic": "Sports",
    "article": "Moises Henriques, the Australian all-rounder, has signed to play for Surrey in this summer's NatWest T20 Blast. He will join after the IPL and is expected to strengthen the squad throughout the campaign.",
}
formatted_prompt = prompt.format(variables=prompt_vars)

# Make a request with your Prompt using OpenAI
from openai import OpenAI

oai_client = OpenAI()
resp = oai_client.chat.completions.create(**formatted_prompt)
print(resp.choices[0].message.content)

Datasets

Manage evaluation datasets and examples for experiments and evaluation:

from phoenix.client import Client
import pandas as pd

client = Client()

# List all available datasets
datasets = client.datasets.list()
for dataset in datasets:
    print(f"Dataset: {dataset['name']} ({dataset['example_count']} examples)")

# Get a specific dataset with all examples
dataset = client.datasets.get_dataset(dataset="qa-evaluation")
print(f"Dataset {dataset.name} has {len(dataset)} examples")

# Convert dataset to pandas DataFrame for analysis
df = dataset.to_dataframe()
print(df.columns)  # Index(['input', 'output', 'metadata'], dtype='object')

# Create a new dataset from dictionaries
dataset = client.datasets.create_dataset(
    name="customer-support-qa",
    dataset_description="Q&A dataset for customer support evaluation",
    inputs=[
        {"question": "How do I reset my password?"},
        {"question": "What's your return policy?"},
        {"question": "How do I track my order?"},
    ],
    outputs=[
        {
            "answer": "You can reset your password by clicking the 'Forgot Password' link on the login page."
        },
        {"answer": "We offer 30-day returns for unused items in original packaging."},
        {"answer": "You can track your order using the tracking number sent to your email."},
    ],
    metadata=[
        {"category": "account", "difficulty": "easy"},
        {"category": "policy", "difficulty": "medium"},
        {"category": "orders", "difficulty": "easy"},
    ],
)

# Create dataset from pandas DataFrame
df = pd.DataFrame(
    {
        "prompt": ["Hello", "Hi there", "Good morning"],
        "response": [
            "Hi! How can I help?",
            "Hello! What can I do for you?",
            "Good morning! How may I assist?",
        ],
        "sentiment": ["neutral", "positive", "positive"],
        "length": [20, 25, 30],
    }
)

dataset = client.datasets.create_dataset(
    name="greeting-responses",
    dataframe=df,
    input_keys=["prompt"],  # Columns to use as input
    output_keys=["response"],  # Columns to use as expected output
    metadata_keys=["sentiment", "length"],  # Additional metadata columns
)

Traces

Retrieve traces for a project with optional filtering and sorting:

from phoenix.client import Client

client = Client()

# Get the latest 100 traces
traces = client.traces.get_traces(project_identifier="my-llm-app")
for trace in traces:
    print(f"Trace {trace.trace_id}: {trace.status} ({trace.latency_ms}ms)")

# Filter by time range
from datetime import datetime, timedelta

traces = client.traces.get_traces(
    project_identifier="my-llm-app",
    start_time=datetime.now() - timedelta(hours=24),
    end_time=datetime.now(),
    sort="latency_ms",
    order="desc",
    limit=50,
)

# Include full span details
traces = client.traces.get_traces(
    project_identifier="my-llm-app",
    include_spans=True,  # caution: can increase response size significantly
    limit=10,
)

# Filter by session
traces = client.traces.get_traces(
    project_identifier="my-llm-app",
    session_id="my-session-id",
)

# Filter with an expression (requires Phoenix server >= 20.12.0)
traces = client.traces.get_traces(
    project_identifier="my-llm-app",
    filter="error_count > 0 and latency_ms >= 1000",
)

Async usage:

from phoenix.client import AsyncClient

async_client = AsyncClient()

traces = await async_client.traces.get_traces(
    project_identifier="my-llm-app",
    limit=50,
)
Parameter Type Default Description
project_identifier str — Project name or ID — required
start_time datetime | None None Inclusive lower bound on trace start time
end_time datetime | None None Exclusive upper bound on trace start time
sort "start_time" | "latency_ms" | None None Sort field (server defaults to "start_time")
order "asc" | "desc" | None None Sort direction (server defaults to "desc")
include_spans bool False Include full span details for each trace
session_id str | Sequence[str] | None None Filter by session ID(s) or GlobalID(s)
filter str | None None Trace filter expression
error bool | None None Deprecated: only traces with (True) or without (False) errored spans
min_latency_ms float | None None Deprecated: inclusive lower bound on trace latency (ms)
max_latency_ms float | None None Deprecated: inclusive upper bound on trace latency (ms)
limit int 100 Maximum number of traces to return
timeout int | None 60 Request timeout in seconds

Note: Requires Phoenix server >= 13.15.0. filter requires >= 20.12.0, and error, min_latency_ms, and max_latency_ms require >= 20.8.0.

error, min_latency_ms, and max_latency_ms are deprecated. Use error_count > 0 / error_count == 0, latency_ms >= N, and latency_ms <= N in filter instead. Deprecated parameters are combined with filter using AND, and an empty filter does not filter.

Spans

Query for spans and annotations from your projects for custom evaluation and annotation workflows:

from phoenix.client import Client
from phoenix.client.types.spans import SpanQuery
from datetime import datetime, timedelta

client = Client()

# Get spans as pandas DataFrame for analysis
spans_df = client.spans.get_spans_dataframe(
    project_identifier="my-llm-app",
    limit=1000,
    query=SpanQuery().where("parent_id is None"),  # Only top-level spans
    start_time=datetime.now() - timedelta(hours=24),
)

# Get span annotations as DataFrame
annotations_df = client.spans.get_span_annotations_dataframe(
    spans_dataframe=spans_df,  # Use spans from previous query
    project_identifier="my-llm-app",
    include_annotation_names=["relevance", "accuracy"],  # Only specific annotations
    exclude_annotation_names=["note"],  # Exclude UI notes
)

# Get the 100 spans that started most recently (requires Phoenix server >= 20.16.0).
# Without sort="start_time", spans are ordered by insertion, not by start time.
recent_spans = client.spans.get_spans(
    project_identifier="my-llm-app",
    sort="start_time",
    order="desc",
    limit=100,
)

Annotations

Add annotations to spans for evaluation, user feedback, and custom annotation workflows:

from phoenix.client import Client

client = Client()

# Add a single annotation with human feedback
client.spans.add_span_annotation(
    span_id="span-123",
    annotation_name="helpfulness",
    annotator_kind="HUMAN",
    label="helpful",
    score=0.9,
    explanation="Response directly answered the user's question",
)

# Bulk annotation logging for multiple spans
annotations = [
    {
        "name": "sentiment",
        "span_id": "span-123",
        "annotator_kind": "LLM",
        "result": {"label": "positive", "score": 0.8},
    },
    {
        "name": "accuracy",
        "span_id": "span-456",
        "annotator_kind": "HUMAN",
        "result": {"label": "accurate", "score": 0.95},
    },
]
client.spans.log_span_annotations(span_annotations=annotations)

Sessions

Retrieve and annotate conversation sessions:

from phoenix.client import Client

client = Client()

# List sessions for a project
sessions = client.sessions.list(project_name="my-llm-app")
for session in sessions:
    print(f"Session: {session['session_id']}")

# Filter sessions with an expression (requires Phoenix server >= 20.12.0)
sessions = client.sessions.list(
    project_name="my-llm-app",
    filter="num_traces > 5 and total_cost > 0.50",
)

# Get conversation turns for a session
turns = client.sessions.get_session_turns(session_id="my-session-id")
for turn in turns:
    print(f"Input: {turn.get('input', {}).get('value')}")
    print(f"Output: {turn.get('output', {}).get('value')}")

# Add a session-level annotation
client.sessions.add_session_annotation(
    session_id="my-session-id",
    annotation_name="user-satisfaction",
    label="satisfied",
    score=0.9,
    annotator_kind="HUMAN",
)

Experiments

Run tasks across datasets and evaluate their outputs:

from phoenix.client import Client

client = Client()

# Get an existing dataset to run the experiment on
dataset = client.datasets.get_dataset(dataset="my-dataset")


# Define a task function
def my_task(example):
    # Your LLM call or business logic here
    return f"Result for: {example['input']['question']}"


# Run an experiment
experiment = client.experiments.run_experiment(
    dataset=dataset,
    task=my_task,
    experiment_name="my-experiment",
)

# Retrieve an existing experiment
ran_experiment = client.experiments.get_experiment(experiment_id="my-experiment-id")
for run in ran_experiment["task_runs"]:
    print(f"Output: {run['output']}, Error: {run['error']}")

Beyond the batch run_experiment loop, you can post runs and evaluations one at a time with log_run and log_evaluation. These are the incremental primitives the pytest plugin builds on, and they are useful for any consumer that produces results progressively rather than all at once:

from datetime import datetime, timezone

# Record a single run against an existing experiment and example
run = client.experiments.log_run(
    experiment_id="my-experiment-id",
    dataset_example_id="my-example-id",
    output="the task output",
    start_time=datetime.now(timezone.utc),
    end_time=datetime.now(timezone.utc),
)

# Attach an evaluation (annotation) to that run
client.experiments.log_evaluation(
    experiment_run_id=run["id"],
    name="exact_match",
    annotator_kind="CODE",
    score=1.0,
    label="correct",
)

Both methods are available on AsyncClient as awaitable coroutines with the same signatures.

Eval CI (pytest)

Write LLM evals as ordinary pytest tests and record each marked test as a run in a Phoenix experiment, so the same suite that gates your pull requests also builds a history of results in Phoenix. Install the pytest extra and mark tests with @pytest.mark.phoenix:

pip install "arize-phoenix-client[pytest]" pytest
import pytest
from phoenix.client.pytest import evaluate, log_evaluation, log_output


@pytest.mark.phoenix(dataset="qa-suite")
@pytest.mark.parametrize("question,expected", [("2+2?", "4")], ids=["arithmetic"])
def test_answers(question, expected):
    result = my_app(question)
    log_output(result)
    log_evaluation(name="exact_match", score=float(result == expected))
    assert result == expected

See the Eval CI with pytest guide for marker options, environment variables, and a CI recipe.

Projects

Manage Phoenix projects that organize your AI application data:

from phoenix.client import Client

client = Client()

# List all projects
projects = client.projects.list()
for project in projects:
    print(f"Project: {project['name']} (ID: {project['id']})")

# Filter server-side by a case-insensitive substring of the project name
support_projects = client.projects.list(name_contains="support")

# Create a new project
new_project = client.projects.create(
    name="Customer Support Bot",
    description="Traces and evaluations for our customer support chatbot",
)
print(f"Created project with ID: {new_project['id']}")

Documentation

Community

Join our community to connect with thousands of AI builders:

  • 🌍 Join our Slack community.
  • 💡 Ask questions and provide feedback in the #phoenix-support channel.
  • 🌟 Leave a star on our GitHub.
  • 🐞 Report bugs with GitHub Issues.
  • 𝕏 Follow us on 𝕏.
  • 💼 Follow us on LinkedIn.
  • 🗺️ Check out our roadmap to see where we're heading next.

Metadata

Release files for arize-phoenix-client 3.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for arize-phoenix-client 3.6.0
File Size Uploaded Provenance Actions
arize_phoenix_client-3.6.0.tar.gz 310.3 kB With provenance Details for arize_phoenix_client-3.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for arize-phoenix-client 3.6.0
File Interpreter ABI Platform Actions
arize_phoenix_client-3.6.0-py3-none-any.whl Python 3 none any Details for arize_phoenix_client-3.6.0-py3-none-any.whl

Total release size: 578.6 kB

Release files / arize_phoenix_client-3.6.0.tar.gz

Download URL arize_phoenix_client-3.6.0.tar.gz
Size 310.3 kB
Tags Source
SHA-256 checksum
How to use checksums
096733f0b95ac3456e1bd99ae639c2ae3b0b395ac1c651eefd050fd1ecb9c215
BLAKE2b-256 checksum
How to use checksums
6bf3350ee5e56455f0813bf93bbd351c8be2d159babcb74cef46af058582a5b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / arize_phoenix_client-3.6.0-py3-none-any.whl

Download URL arize_phoenix_client-3.6.0-py3-none-any.whl
Size 268.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6ab26e95fb2cc57d5e289471a4aa12095fee44e930531320c2be0cbdcd5dd3f6
BLAKE2b-256 checksum
How to use checksums
1abb0add971fcf095ca2f0ea9bdd73599db1abb52a4482eae6015debba6e3cca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Security for arize-phoenix-client 3.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for arize_phoenix_client-3.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

3.6.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page