> ## Documentation Index
> Fetch the complete documentation index at: https://arizeai-433a7140.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudflare AI Gateway Tracing

> Configure Cloudflare AI Gateway to send traces to Phoenix by exporting the gateway's OpenTelemetry spans or by instrumenting your app with OpenInference.

Configure Cloudflare AI Gateway to send traces to Phoenix, either by exporting the gateway's spans
(no application code) or by instrumenting your application with OpenInference.

## Prerequisites

* A [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/). Create one in the
  Cloudflare dashboard under **AI → AI Gateway**.
* A running Phoenix instance (see [Launch Phoenix](#launch-phoenix)). To export gateway spans,
  Cloudflare must be able to reach your Phoenix collector.
* Python 3.10+ (only to instrument your application).

## Launch Phoenix

<Card>
  <Tabs>
    <Tab title="Local">
      ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      uvx arize-phoenix serve
      ```

      No [uv](https://docs.astral.sh/uv/)? `pip install arize-phoenix && phoenix serve` does the same thing. See [Terminal setup](/docs/phoenix/environments#terminal) for customization.
    </Tab>

    <Tab title="Container">
      ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      docker run -p 6006:6006 -p 4317:4317 arizephoenix/phoenix:latest
      ```

      Images are published to [Docker Hub](https://hub.docker.com/r/arizephoenix/phoenix). See [Docker](/docs/phoenix/self-hosting/deployment-options/docker) for volumes, PostgreSQL, and other options.
    </Tab>

    <Tab title="Self-Host">
      Run Phoenix on your own infrastructure, backed by PostgreSQL so traces persist beyond a single process. This is the option to reach for once Phoenix is shared across a team or environment.

      The [self-hosting guide](/docs/phoenix/self-hosting) covers [Kubernetes](/docs/phoenix/self-hosting/deployment-options/kubernetes), [Helm](/docs/phoenix/self-hosting/deployment-options/kubernetes-helm), [Railway](/docs/phoenix/self-hosting/deployment-options/railway), [AWS CloudFormation](/docs/phoenix/self-hosting/deployment-options/aws-with-cloudformation), [Google Cloud Run](/docs/phoenix/self-hosting/deployment-options/google-cloud-run), [Azure](/docs/phoenix/self-hosting/deployment-options/azure), and [Render](/docs/phoenix/self-hosting/deployment-options/render), plus authentication and configuration.
    </Tab>
  </Tabs>

  Phoenix serves its UI and OTLP HTTP on port **6006**, and OTLP gRPC on port **4317**. For a local instance that's [http://localhost:6006](http://localhost:6006) — leave it running while you work.
</Card>

<Note>
  To export gateway spans, AI Gateway sends them from Cloudflare's edge, so Cloudflare must be able
  to reach your Phoenix collector. A deployed Phoenix endpoint can receive spans directly. To use a
  local endpoint, expose it with a tunnel such as [cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/).
</Note>

## Set up tracing

<Tabs>
  <Tab title="Export gateway spans">
    This option does not require application code. The gateway exports a span for each request it
    proxies.

    In the Cloudflare dashboard, open your gateway, go to **Settings → Otel Integration → Add
    Destination**, and enter these values:

    1. **OTLP Traces Endpoint**: your Phoenix endpoint with `/v1/traces` appended (for a local instance
       exposed through a tunnel, use `https://<your-tunnel-hostname>/v1/traces`).
    2. **Content Type**: select **Protobuf**.
    3. **Custom Headers**: add `x-project-name` set to the Phoenix project you want traces to land in.
       Phoenix creates the project on the first span.

    <Warning>
      Set **Content Type** to **Protobuf**, not the default **JSON**. Phoenix's trace endpoint accepts
      only Protobuf, and a destination left on JSON is rejected before any spans arrive.
    </Warning>

    <Note>
      If your Phoenix requires an API key, the destination also needs an `Authorization` value of
      `Bearer <your-phoenix-api-key>`. Cloudflare can send this value as a header or read it from a
      Secrets Store attached to the gateway. Some gateways reject a plain header and require the Secrets
      Store. Use Cloudflare's [OTel integration docs](https://developers.cloudflare.com/ai-gateway/observability/otel-integration/)
      for the current setup steps.
    </Note>

    Save the destination, then send traffic through the gateway. Cloudflare exports spans in batches, so
    wait a minute or two for them to appear.

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    curl "https://gateway.ai.cloudflare.com/v1/<account-id>/<gateway-name>/openai/chat/completions" \
      --header "Authorization: Bearer <provider-api-key>" \
      --header "Content-Type: application/json" \
      --data '{"model":"gpt-5-mini","messages":[{"role":"user","content":"Hello from Cloudflare AI Gateway"}]}'
    ```
  </Tab>

  <Tab title="Instrument your app">
    Trace the OpenAI client in your application, and route requests through the gateway's
    OpenAI-compatible endpoint. Phoenix captures full input and output messages, so prompts and
    responses render in Phoenix. The `/compat` endpoint lets the OpenAI SDK reach any provider the
    gateway supports by setting `model` to `provider/model` (for example `openai/gpt-5-mini` or
    `workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast`).

    Install the packages:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    pip install arize-phoenix-otel openinference-instrumentation-openai openai
    ```

    Set your environment variables:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    export PHOENIX_COLLECTOR_ENDPOINT="<your-phoenix-collector-endpoint>"  # use http://localhost:6006 for local Phoenix
    export PHOENIX_API_KEY="<your-phoenix-api-key>"          # required for Phoenix Cloud or authenticated Phoenix
    export OPENAI_API_KEY="<your-provider-api-key>"
    export CLOUDFLARE_ACCOUNT_ID="<your-cloudflare-account-id>"
    export CLOUDFLARE_AI_GATEWAY_NAME="<your-gateway-name>"
    ```

    Register Phoenix and instrument the OpenAI client:

    ```python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    import os
    from phoenix.otel import register
    from openinference.instrumentation.openai import OpenAIInstrumentor
    from openai import OpenAI

    tracer_provider = register(project_name="cloudflare-ai-gateway")
    OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)

    client = OpenAI(
        base_url=(
            "https://gateway.ai.cloudflare.com/v1/"
            f"{os.environ['CLOUDFLARE_ACCOUNT_ID']}/"
            f"{os.environ['CLOUDFLARE_AI_GATEWAY_NAME']}/compat"
        ),
        api_key=os.environ["OPENAI_API_KEY"],
    )

    response = client.chat.completions.create(
        model="openai/gpt-5-mini",
        messages=[{"role": "user", "content": "Hello from Cloudflare AI Gateway"}],
    )
    ```

    `register()` reads `PHOENIX_COLLECTOR_ENDPOINT` and `PHOENIX_API_KEY` from the environment. For a
    local Phoenix instance, no other Phoenix configuration is needed.

    <Note>
      If your gateway has Authenticated Gateway enabled, also pass its token when you create the client,
      for example `default_headers={"cf-aig-authorization": "Bearer <gateway-token>"}` in the
      `OpenAI(...)` call.
    </Note>
  </Tab>
</Tabs>

## Link gateway spans to your app's traces

When you export gateway spans, you can nest the gateway span under an existing application span
instead of starting a new trace. Pass the parent context to the gateway request with these headers:

| Header                       | Value                                                     |
| ---------------------------- | --------------------------------------------------------- |
| `cf-aig-otel-trace-id`       | the active trace ID (32-character hex string)             |
| `cf-aig-otel-parent-span-id` | the parent span ID to attach to (16-character hex string) |

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl "https://gateway.ai.cloudflare.com/v1/<account-id>/<gateway-name>/openai/chat/completions" \
  --header 'cf-aig-otel-trace-id: a1b2c3d4e5f60718293a4b5c6d7e8f90' \
  --header 'cf-aig-otel-parent-span-id: 1122334455667788' \
  --header 'Content-Type: application/json' \
  --data '{"model":"gpt-5-mini","messages":[{"role":"user","content":"Hello"}]}'
```

## Add custom metadata

Attach your own key/value metadata to gateway requests with the `cf-aig-metadata` header (JSON).
Cloudflare exports each key and value as a span attribute in Phoenix, so you can filter and group by
metadata such as user, team, environment, or tenant.

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
--header 'cf-aig-metadata: {"environment":"production","team":"platform"}'
```

Do not put secrets or sensitive personal data in metadata. Phoenix stores these values as span
attributes visible to anyone with access to the project.

## What renders in Phoenix

* **Gateway export:** each proxied request is an **LLM span** with the model name and token counts
  populated. The provider, cost, and full prompt and response are stored under the span's
  **Attributes**.
* **App instrumentation (OpenInference):** spans include the model, token counts, and the prompt and
  response rendered in the formatted message view.

## Troubleshooting

* **No spans arriving (gateway export):** confirm **Content Type** is **Protobuf** (JSON is
  rejected), the endpoint ends in `/v1/traces`, and Cloudflare can reach your Phoenix collector.
* **Spans in the wrong project:** set the `x-project-name` header (gateway export) or `project_name`
  in `register()` (app instrumentation).
* **Nothing yet:** Cloudflare exports in batches, so send a few requests and wait a minute or two.

## Resources

<Columns cols={2}>
  <Card title="Cloudflare AI Gateway OTEL docs" href="https://developers.cloudflare.com/ai-gateway/observability/otel-integration/" icon="book" horizontal description="Cloudflare's collector configuration reference" />

  <Card title="OpenTelemetry Gen AI semantics" href="https://opentelemetry.io/docs/specs/semconv/gen-ai/" icon="puzzle-piece" horizontal description="The conventions AI Gateway emits" />
</Columns>
