---
title: "OpenAI Codex (OTel)"
canonical_url: "https://docs.getdx.com/connectors/codex-otel/"
md_url: "https://docs.getdx.com/connectors/codex-otel.md"
last_updated: "2026-08-27"
---

# OpenAI Codex (OTel)
By integrating Codex with DX via OpenTelemetry (OTel), you can import per-user daily usage metrics including thread counts, conversation turns, and per-model token consumption.

Use the [schema explorer](https://docs.getdx.com/schema/) to see the Codex tables DX imports.

## How it works

Codex supports OpenTelemetry Protocol (OTLP) export for usage telemetry. When configured, Codex sends OTLP metrics directly to DX.

DX accepts Codex metrics at a dedicated OTLP HTTP endpoint and processes them into the Codex daily usage tables. The connector imports:

- **Threads** - New Codex threads started.
- **Turns** - User and assistant turns per thread.
- **Token usage** - Uncached input, cached input, output, and total tokens by model.
- **Client** - The Codex client that reported the usage (`originator`), such as the CLI.

DX processes delta metrics. Set Codex to export metrics with delta temporality because cumulative metrics are ignored.

This connector can run alongside the [OpenAI Codex (Enterprise)](https://docs.getdx.com/connectors/codex-enterprise/) connector. Both write to the `codex_` tables and rows are tagged with a `source` column (`enterprise` or `otel`). Where both connectors report the same user and day, DX reports the OTel row, because it covers Codex usage from the developer's machine whether or not it ran inside your Enterprise workspace. Enterprise API rows cover the users and days OTel has no data for.

## Prerequisites

To connect Codex to DX, you need:

- DX admin access to create a data connector.
- Codex installed on each developer machine where telemetry should be collected.
- A Codex version that supports OTel metric export.
- Permission to edit the user-level Codex config file (`~/.codex/config.toml`) and set environment variables for Codex users, or to push managed configuration or an MDM profile to those machines.
- Outbound HTTPS access from developer machines to your DX API host.

## Setup instructions

Follow the steps below to connect Codex to DX via OTel.

#### Step 1

Navigate to the connections page in DX and select **+ Connection** in the top right.

Select **OpenAI Codex (OTel)** as the connector type and save the connection. DX will generate a secure ingest token for the connection.

#### Step 2

Copy the ingest token from the connection settings page. The token is separate from your DX API token and is used only by the Codex OTel endpoint.

#### Step 3

Configure Codex telemetry in `~/.codex/config.toml`. Set the exporter endpoint to your DX API host with `/api/codex/v1/metrics` appended.

```toml
[otel.metrics_exporter.otlp-http]
endpoint = "https://<your-dx-host>/api/codex/v1/metrics"
protocol = "json"
headers = { "Authorization" = "Bearer <CODEX_OTEL_INGEST_TOKEN>" }
```

The connection settings page in DX generates this exact `[otel]` block for your host and token — copy it directly from there.

Editing `~/.codex/config.toml` on every machine does not scale, so admins can push the same `[otel]` block to the fleet through [managed configuration](https://learn.chatgpt.com/docs/enterprise/managed-configuration) instead. Telemetry settings travel as **managed defaults**, which Codex applies when a client starts and reapplies on each launch. On macOS these can also be delivered by MDM: push a device profile under the `com.openai.codex` preference domain with the base64-encoded TOML (no line wrapping) in the `config_toml_base64` key, using tooling such as Jamf Pro, Fleet, or Kandji.

Managed defaults take precedence over a developer's own `config.toml`, so telemetry cannot accidentally be pointed somewhere else, but it also means DX telemetry stops flowing if the managed payload is removed. Because the block carries the DX ingest token, treat the managed payload as a secret under the same change control as any other managed setting.

Codex's admin-enforced [`requirements.toml`](https://learn.chatgpt.com/docs/enterprise/managed-configuration#admin-enforced-requirements-requirementstoml) is a separate layer. It constrains security-sensitive settings such as approval policy, sandbox mode, permission profiles, and feature flags, rather than exporter endpoints, so it is not where the `[otel]` block belongs. It is still worth reviewing alongside this connector: if your requirements deny network access for the sandbox, confirm your developers can still reach your DX API host.

For the full list of Codex telemetry settings, see the [Codex configuration docs](https://learn.chatgpt.com/docs/config-file/config-advanced).

#### Step 4

Start Codex with the OTel environment variables below:

```sh
export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta"
export OTEL_RESOURCE_ATTRIBUTES="user.email=<USER_EMAIL>"
codex
```

Set `OTEL_RESOURCE_ATTRIBUTES` separately for each developer. Codex telemetry contains no user identity of its own, so DX uses `user.email` to link Codex activity to DX users. If `user.email` is missing or invalid, DX skips the metric data because it cannot attribute the activity to a user.

Both variables have to be set in the shell that launches Codex, and Codex only reads them at startup. Either export them in the same session immediately before running `codex`, as above, or add them to your shell startup file — `~/.zshrc`, `~/.bashrc`, or `~/.bash_profile`, depending on your shell — so that every new session has them. Putting them in a startup file is the option that scales: a session that happens to be missing them still sends telemetry, but DX discards it, and the gap is only visible later as absent data.

> **Note**: White space is not allowed in `OTEL_RESOURCE_ATTRIBUTES`. Replace spaces with `%20`.

## Ingest endpoint

DX exposes the following OTLP HTTP endpoint for receiving Codex telemetry.


| Endpoint | Signal |
| -------- | ------ |
| POST /api/codex/v1/metrics | Metrics (threads, turns, tokens by model and client) |


Requests are authenticated with a `Bearer` token in the `Authorization` header. DX accepts JSON OTLP metric payloads for this endpoint.

Codex logs and traces are not imported by this connector. Leave `otel.exporter` and `otel.trace_exporter` unset (or set to `"none"`) so that only metrics are exported to DX.

## Verify data in DX

After Codex sends telemetry, wait for the OTel processing job to run. DX processes pending Codex OTel events every 10 minutes.

Go to **DX** -> **Data Studio** and run the following query:

```sql
SELECT
    cu.email,
    COUNT(cdu.id) AS metric_count,
    MIN(cdu.date) AS earliest_date,
    MAX(cdu.date) AS latest_date,
    COUNT(CASE WHEN cdu.is_active = true THEN 1 END) AS active_days
FROM codex_daily_usages cdu
JOIN codex_users cu ON cu.id = cdu.user_id
WHERE cdu.source = 'otel'
GROUP BY cu.email
HAVING COUNT(cdu.id) > 0
ORDER BY metric_count DESC, cu.email
```

If the connector is working, the query returns Codex users with daily activity. Use the [schema explorer](https://docs.getdx.com/schema/) to inspect the full `codex_` table family.

## Troubleshooting

#### No data appearing in DX after setup

- Confirm the `[otel]` block is in the user-level config (`~/.codex/config.toml`) or a managed configuration payload, not a project-level config.
- Confirm `[otel.metrics_exporter.otlp-http]` sets `endpoint` to `/api/codex/v1/metrics` on your DX API host, `protocol` to `"json"`, and an `Authorization` header carrying the ingest token from the **OpenAI Codex (OTel)** connection settings page.
- If you distribute the block centrally, confirm the managed payload is actually applied. Codex prints the effective config summary at startup, and managed defaults only reload when the client restarts.
- Confirm Codex was started with `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta`.
- Confirm `OTEL_RESOURCE_ATTRIBUTES` includes a valid `user.email` value for the developer running Codex.

#### Data is attributed to the wrong user

Check the `user.email` value in `OTEL_RESOURCE_ATTRIBUTES` on the affected machine. If you distribute this configuration centrally, template the email value per developer instead of using a shared static value.

#### Credits and cost are missing

OTel telemetry does not report credit usage, so `total_credits` is `0` for rows with `source = 'otel'`. Credit and spend reporting requires the [OpenAI Codex (Enterprise)](https://docs.getdx.com/connectors/codex-enterprise/) connector.
---

## Sitemap

[Overview of all docs pages](/llms.txt)
