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

# Cloudflare AI Gateway

> Export Cloudflare AI Gateway OpenTelemetry spans to Arize AX over OTLP for LLM observability.

[Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) can export gateway spans to OpenTelemetry-compatible backends over OTLP. Send those spans to Arize AX to inspect model, provider, token usage, latency, prompt, completion, cost, and custom metadata for requests routed through your gateway.

<Note>
  This page covers two complementary paths: Cloudflare AI Gateway's own OTLP export, and app-side OpenInference tracing for OpenAI-compatible requests that route through Cloudflare. Neither path requires a Cloudflare-specific OpenInference instrumentor.
</Note>

## Prerequisites

* A Cloudflare AI Gateway
* Python 3.9+ if you want app-side OpenInference tracing
* An Arize AX account ([sign up](https://arize.com/sign-up/))
* Your Arize AX **Space ID** and **API Key**

## Launch Arize AX

1. Sign in to your [Arize AX account](https://app.arize.com/).
2. From **Space Settings**, copy your **Space ID** and **API Key**.

## Option 1: export gateway spans from Cloudflare

In the Cloudflare dashboard:

1. Open your AI Gateway.
2. Go to **Settings**.
3. Add an OpenTelemetry exporter.
4. Set the exporter URL to the Arize AX OTLP/HTTP traces endpoint:

```text theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
https://otlp.arize.com/v1/traces
```

For EU spaces, use:

```text theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
https://otlp.eu-west-1a.arize.com/v1/traces
```

Set the exporter content type to **protobuf**.

Add these headers:

```text theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
space_id=<your-arize-space-id>
api_key=<your-arize-api-key>
```

<Note>
  Cloudflare AI Gateway lets you attach custom metadata to requests with the `cf-aig-metadata` header. Those values are exported as span attributes, so they are useful for user, team, environment, or tenant filters in Arize AX. Do not include secrets or sensitive personal data.
</Note>

## Send a gateway request

Send traffic through the gateway as usual. For example, with the OpenAI-compatible route:

```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" \
  --header 'cf-aig-metadata: {"environment":"production","team":"platform"}' \
  --data '{
    "model": "gpt-5.4-mini",
    "messages": [{"role": "user", "content": "Explain why OTLP is useful for AI Gateway tracing."}]
  }'
```

## Option 2: trace OpenAI-compatible app calls

If your application uses the OpenAI SDK against Cloudflare AI Gateway's `/compat` endpoint, use the OpenInference OpenAI instrumentor. This captures the application-side request and response, while the Cloudflare exporter captures gateway-side spans.

Install the client-side packages:

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

Configure credentials:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export ARIZE_SPACE_ID="<your-space-id>"
export ARIZE_API_KEY="<your-api-key>"
export ARIZE_PROJECT_NAME="cloudflare-ai-gateway-example"
export OPENAI_API_KEY="<your-provider-api-key>"
export CLOUDFLARE_ACCOUNT_ID="<your-cloudflare-account-id>"
export CLOUDFLARE_AI_GATEWAY_NAME="<your-gateway-name>"
```

Set up tracing before creating the OpenAI client:

```python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
# instrumentation.py
import os

from arize.otel import register
from openinference.instrumentation.openai import OpenAIInstrumentor

tracer_provider = register(
    space_id=os.environ["ARIZE_SPACE_ID"],
    api_key=os.environ["ARIZE_API_KEY"],
    project_name=os.environ["ARIZE_PROJECT_NAME"],
)

OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)
print("Arize AX tracing initialized for Cloudflare AI Gateway calls.")
```

Route the OpenAI-compatible request through Cloudflare:

```python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
# example.py
import os

from instrumentation import tracer_provider  # noqa: F401
from openai import OpenAI

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.4-mini",
    messages=[
        {
            "role": "user",
            "content": "Explain why OTLP is useful for AI Gateway tracing.",
        }
    ],
)

print(response.choices[0].message.content)
```

Cloudflare AI Gateway supports multiple providers through the same `/compat` route. Use the provider API key and provider-prefixed model name that match the model you route through the gateway.

## Verify in Arize

1. Open your Arize AX space.
2. Look for gateway spans within \~30 seconds.
3. If you do not set an OpenInference project resource attribute through a collector, the spans may appear in the default project.

### Check from the skill, CLI, or SDK

Confirm spans are actually reaching your Arize AX project. Use whichever fits your workflow — the skill and CLI work for any framework; the SDK check is shown for each language.

<Tabs>
  <Tab title="Arize skill (agent)">
    Install the [Arize Skills](https://github.com/Arize-ai/arize-skills) plugin and let your coding agent check for you:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    npx skills add Arize-ai/arize-skills
    ```

    Then prompt your agent:

    > Use the `arize-trace` skill to export and analyze recent traces from my project. Confirm spans are arriving, and summarize any errors or latency issues.
  </Tab>

  <Tab title="AX CLI">
    Export recent spans for your project — any rows mean traces are landing:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    ax spans export "$ARIZE_PROJECT_NAME" --space "$ARIZE_SPACE_ID" \
      --limit 5 --stdout | jq 'length'
    ```

    A non-zero count confirms spans reached Arize AX. Run `ax auth login` first if you have not authenticated. See the [`ax spans` reference](/docs/api-clients/cli/spans).
  </Tab>

  <Tab title="SDK">
    Query the project's spans and check that at least one came back.

    <CodeGroup>
      ```python Python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      import os
      from arize import ArizeClient

      client = ArizeClient(api_key=os.environ["ARIZE_API_KEY"])
      resp = client.spans.list(
          project=os.environ["ARIZE_PROJECT_NAME"],
          space=os.environ["ARIZE_SPACE_ID"],
          limit=5,
      )
      count = len(resp.spans)
      print(
          f"{count} span(s) found" if count else "No spans yet — recheck setup"
      )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      // Reads ARIZE_API_KEY from the environment.
      import { listSpans } from "@arizeai/ax-client";

      const { data: spans } = await listSpans({
        project: process.env.ARIZE_PROJECT_NAME!,
        space: process.env.ARIZE_SPACE_ID!,
        limit: 5,
      });
      const count = spans.length;
      console.log(
        count ? `${count} span(s) found` : "No spans yet — recheck setup",
      );
      ```

      ```go Go theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      client, err := arize.NewClient(
          arize.Config{APIKey: os.Getenv("ARIZE_API_KEY")},
      )
      if err != nil {
          log.Fatal(err)
      }
      resp, err := client.Spans.List(ctx, spans.ListRequest{
          Project: os.Getenv("ARIZE_PROJECT_NAME"),
          Space:   os.Getenv("ARIZE_SPACE_ID"),
          Limit:   5,
      })
      if err != nil {
          log.Fatal(err)
      }
      fmt.Printf("%d span(s) found\n", len(resp.Spans))
      ```
    </CodeGroup>

    SDK span references: [Python](/docs/api-clients/python/version-8/client-resources/spans) · [TypeScript](/docs/api-clients/typescript/version-1/client-resources/spans) · [Go](/docs/api-clients/go/version-2/client-resources/spans).
  </Tab>
</Tabs>

## What Arize captures

Cloudflare AI Gateway exports spans using OpenTelemetry GenAI semantic conventions. Arize AX can ingest those spans and render the model request alongside attributes such as:

* model and provider
* input and output token counts
* prompt and completion JSON
* estimated cost
* custom metadata from `cf-aig-metadata`
* trace context, if you pass Cloudflare's trace context headers

## Optional: add a project name with an OpenTelemetry Collector

Arize AX uses the `openinference.project.name` resource attribute to organize spans into projects. Cloudflare AI Gateway's direct exporter focuses on endpoint, headers, and content type. If you want these spans in a named AX project instead of the default project, send the gateway export to an OpenTelemetry Collector first and add a resource processor:

```yaml theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
processors:
  resource/arize_project:
    attributes:
      - key: openinference.project.name
        value: cloudflare-ai-gateway
        action: upsert
```

Then export from the collector to Arize AX over OTLP/HTTP with the same `space_id` and `api_key` headers.

## Troubleshooting

* **No traces in Arize.** Confirm the exporter URL is `https://otlp.arize.com/v1/traces`, the content type is protobuf, and both Arize headers are present.
* **Traces appear in the default project.** Add `openinference.project.name` with an OpenTelemetry Collector resource processor.
* **Missing application spans.** Cloudflare AI Gateway traces the gateway request. Use the OpenInference client-side path if you also need prompt, response, chain, tool, retriever, or framework spans from your application.

## Resources

<CardGroup>
  <Card icon="book-open" href="https://developers.cloudflare.com/ai-gateway/observability/otel-integration/" title="Cloudflare AI Gateway OpenTelemetry" horizontal />

  <Card icon="terminal" href="/docs/ax/integrations/opentelemetry/opentelemetry-arize-otel" title="Arize AX OpenTelemetry" horizontal />

  <Card icon="book-open" href="/docs/ax/concepts/otel-openinference/semantic-conventions" title="OpenTelemetry GenAI and OpenInference" horizontal />
</CardGroup>
