> For the complete documentation index, see [llms.txt](https://docs.revenium.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.revenium.io/track-and-control-costs/analyze-ai-tooling-spend/setup-codex.md).

# Setup Codex CLI

Revenium reports Codex CLI spend per developer on the Codex dashboard under **Usage by User**. How each developer is identified depends on how they sign in to Codex: see [Where the configured email applies](#where-the-configured-email-applies). To add earlier usage, import past sessions from each developer's machine, as described in step 7, Backfill historical data.

The Revenium CLI tracks OpenAI Codex CLI usage by writing OTLP configuration to the Codex `config.toml` and injecting a shell wrapper that sets the correct environment for each session.

**Requirements:**

* OpenAI Codex CLI installed and configured
* Revenium API key (`hak_` or `rev_` prefix). Get it from Integrations > SDK Setup in the Revenium dashboard.
* Node.js >= 20.19.0

## 1. Install the Revenium CLI

```bash
npm install -g @revenium/cli
```

You can also use `npx` without installing globally:

```bash
npx --package @revenium/cli revenium-codex setup
```

## 2. Run the setup wizard

```bash
revenium-codex setup
```

The wizard prompts for:

* **Revenium API key** — validated against the `hak_` or `rev_` prefix
* **Email** (optional) — for backfill attribution
* **Organization name** (optional) — for grouping usage
* **Product name** (optional) — for sub-segmenting within the organization
* **API endpoint** (optional) — defaults to `https://api.revenium.ai`
* **Config path** (optional) — defaults to `~/.codex/config.toml`

The wizard tests connectivity to the Revenium endpoint before writing the configuration.

### Where the configured email applies

{% hint style="info" %}
The email you enter here attributes **backfilled** usage — historical Codex sessions imported with `revenium-codex backfill` are attributed to this address.

Live Codex sessions work differently, depending on how you're signed in to Codex:

* **Signed in to Codex via ChatGPT:** live usage is already attributed to your signed-in account automatically. No configuration is needed, and the wizard's email does not change this.
* **Using an API key with Codex (no ChatGPT sign-in):** Codex does not send per-developer identity on live sessions in this mode, so live usage is attributed to your account's default identity. Run a backfill to attribute this usage by email instead.
  {% endhint %}

Configuration is written to the `[otel]` section of `~/.codex/config.toml`. If an existing `[otel]` section is found, the wizard prompts before overwriting (use `--force` to skip the prompt).

The wizard also creates a shell wrapper function so that conflicting OTLP environment variables from other tools are automatically unset before Codex runs.

## 3. Restart your terminal

```bash
exec $SHELL
```

## 4. Verify the configuration

```bash
revenium-codex status
```

Confirms that the Revenium endpoint is reachable with the provided credentials.

You can also point to a custom config path:

```bash
revenium-codex status --config-path /path/to/config.toml
```

## 5. Send a test metric

```bash
revenium-codex test --verbose
```

Sends a zero-cost synthetic event to verify the Revenium pipeline is processing Codex data. Check AI Assistants > Codex > Integration Logs to confirm receipt.

You can also test with a custom config path:

```bash
revenium-codex test --verbose --config-path /path/to/config.toml
```

## 6. Start using Codex CLI

After setup, use Codex CLI as you normally would. The `config.toml` `[otel]` section tells Codex where to send telemetry, and the shell wrapper ensures no conflicting environment variables interfere. Usage appears in Revenium after the next telemetry flush.

## 7. Backfill historical data

To import historical Codex usage from local session logs:

```bash
# Backfill from a specific date:
revenium-codex backfill --since 2025-01-01 --to 2025-06-01

# Preview without sending:
revenium-codex backfill --since 2025-01-01 --to 2025-06-01 --dry-run

# Control batch size:
revenium-codex backfill --since 2025-01-01 --batch-size 50

# Custom sessions path:
revenium-codex backfill --sessions-path /path/to/sessions

# Custom config path:
revenium-codex backfill --config-path /path/to/config.toml

# Verbose output:
revenium-codex backfill --since 2025-01-01 --verbose
```

Backfill is idempotent — deterministic transaction IDs prevent duplicate records.

{% hint style="info" %}
**Shell wrapper:** The setup creates a shell function that wraps the `codex` binary. This function unsets `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS`, `OTEL_EXPORTER_OTLP_PROTOCOL`, and `OTEL_LOGS_EXPORTER` before running Codex, so that environment variables from other tools (like Claude Code or Gemini) do not conflict with Codex's `config.toml` settings.
{% endhint %}

## On the dashboard

Open **Intelligence > AI Assistants > Codex** to see Codex CLI usage and costs after telemetry begins arriving.

## 8. Troubleshooting

Start every diagnosis with `revenium-codex status` — it checks, in order, that the config exists, is in the correct form, has telemetry enabled, and can reach Revenium, and it names the exact fix for whatever it finds.

### No data appears in Revenium after setup

The most common cause is that the current shell is still running without the wrapper that Codex needs. Work through these in order:

1. **Restart your terminal.** Run `exec $SHELL` or open a new terminal window so the shell wrapper installed during setup is active. Codex reads its telemetry environment through that wrapper.
2. **Check the configuration.** Run `revenium-codex status`. It reports whether the `[otel]` config is present and valid and whether the Revenium endpoint is reachable.
3. **Send a synthetic event.** Run `revenium-codex test --verbose`, then open **Intelligence > AI Assistants > Codex** and select **View integration logs** to confirm the event was received. If the test event lands but real sessions do not, Codex is running outside the wrapper. Return to step 1.
4. **Confirm a session has flushed.** Usage appears only after Codex's next telemetry flush, so allow a completed Codex session before expecting data.

### `status` reports "legacy flat-key \[otel] form"

An older or hand-edited `config.toml` can store the `[otel]` settings in a flat form that Codex silently ignores — the configuration looks present but no telemetry is exported. Migrate it to the supported form:

```bash
revenium-codex setup --force
```

### `status` reports missing `[features] runtime_metrics = true`

Codex only emits OpenTelemetry data when runtime metrics are enabled. If this flag is absent, no usage is sent even though the `[otel]` block is otherwise correct. Restore it with:

```bash
revenium-codex setup --force
```

### `status` reports "No Codex config found"

There is no `[otel]` configuration at `~/.codex/config.toml`. Run `revenium-codex setup` to create it. If you keep Codex's config in a non-default location, point the CLI at it:

```bash
revenium-codex status --config-path /path/to/config.toml
```

### Connection check fails, or authentication is rejected

If `status` or `test` reports a failed connection or a rejected key:

* **Verify the key type.** Codex telemetry authenticates with a **Revenium** API key (`hak_` or `rev_` prefix), not an OpenAI or other provider key. A provider key authenticates model calls; it will not authenticate telemetry ingest. Get a Revenium key from **Integrations > SDK Setup** in the Revenium dashboard.
* **Verify the endpoint.** Confirm it matches your Revenium environment. The default is `https://api.revenium.ai`.
* **Re-enter credentials.** Run `revenium-codex setup --force` to rewrite the `[otel]` block with a corrected key or endpoint.
* **Check the network.** If the only error is `fetch failed`, see [Corporate networks: proxy or TLS inspection](#corporate-networks-proxy-or-tls-inspection).

### Corporate networks: proxy or TLS inspection

If `status` or `test` fails and the only error is `fetch failed`, the company network is the likely cause. The Revenium CLI runs on Node.js. By default, Node.js does not use the operating system's certificate store or proxy settings. So a network that inspects TLS traffic, or that requires a web proxy, stops the CLI before it reaches Revenium.

These steps apply to every Revenium CLI command, including `revenium-codex`, `revenium-gemini` and `revenium-metering`. If you chose a custom endpoint during setup, use that endpoint's host instead of `api.revenium.ai` in every command on this page.

#### Step 1: Check

Save this line in a file named `check.js`, in a folder you can find again:

```javascript
fetch('https://api.revenium.ai/meter/v2/otlp/v1/logs',{method:'POST'}).then(async r=>console.log('HTTP',r.status,(await r.text()).slice(0,200))).catch(e=>console.log(e.cause))
```

Run it from the same terminal you use for the CLI:

```bash
node check.js
```

| What it prints                                                                                                                                                   | What it means                                                               | Next step                                                                                                                                                       |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `HTTP 403 {"message":"Forbidden"}`                                                                                                                               | The network path to Revenium is healthy.                                    | Check the key and the endpoint, as described in [Connection check fails, or authentication is rejected](#connection-check-fails-or-authentication-is-rejected). |
| `HTTP 403` with any other text, such as a web page                                                                                                               | A proxy or security appliance on your network answered instead of Revenium. | Ask your IT team to allow `api.revenium.ai`.                                                                                                                    |
| A certificate error such as `DEPTH_ZERO_SELF_SIGNED_CERT`, `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, `UNABLE_TO_GET_ISSUER_CERT_LOCALLY` or `SELF_SIGNED_CERT_IN_CHAIN` | The network inspects TLS traffic, for example Zscaler.                      | Go to step 2.                                                                                                                                                   |
| `ECONNREFUSED`, `ENOTFOUND` or a timeout                                                                                                                         | The network requires a web proxy.                                           | Go to step 3.                                                                                                                                                   |

#### Step 2: Fix the certificate

Node.js must trust the root certificate that your company uses to inspect TLS traffic. Point the `NODE_EXTRA_CA_CERTS` environment variable at a PEM file that holds that root certificate.

The file must hold the root certificate itself. A file with only an intermediate certificate still fails. Your IT team can give you the root certificate as a PEM file. If you have it already, skip to the last command for your system and replace the certificate path in that command with the full path to your PEM file.

Trust only a certificate that your IT team has confirmed. Do these steps on your company network, not on public Wi-Fi, because an attacker on another network causes the same certificate errors. Ask your IT team for the SHA-256 fingerprint of the root certificate. Then compare it with the output of this command, using the path to your PEM file:

```bash
openssl x509 -in <path to PEM file> -noout -fingerprint -sha256
```

If the fingerprints differ, stop and contact your IT team.

{% tabs %}
{% tab title="macOS" %}
Export the root certificate from the System keychain. Replace `<certificate name>` with the name your IT team gives you:

```bash
security find-certificate -c '<certificate name>' -p /Library/Keychains/System.keychain > "$HOME/company-root.pem"
```

Check that it is a root certificate. The `subject` and `issuer` lines must be the same:

```bash
openssl x509 -in "$HOME/company-root.pem" -noout -subject -issuer
```

You can also export it from **Keychain Access**. Select the certificate, choose **File > Export Items** and pick the **Privacy Enhanced Mail (.pem)** format.

Add the setting to your shell profile, then open a new terminal:

```bash
echo 'export NODE_EXTRA_CA_CERTS="$HOME/company-root.pem"' >> ~/.zshrc
```

If you use Fish, run this command instead:

```fish
set -Ux NODE_EXTRA_CA_CERTS "$HOME/company-root.pem"
```

{% endtab %}

{% tab title="Linux" %}
Save the certificates the network sends into separate files:

```bash
mkdir -p ~/company-ca && cd ~/company-ca
openssl s_client -connect api.revenium.ai:443 -servername api.revenium.ai -showcerts </dev/null 2>/dev/null | awk '/BEGIN CERTIFICATE/{n++; on=1} on{print > ("cert-" n ".pem")} /END CERTIFICATE/{on=0}'
```

List each file's subject and issuer:

```bash
for f in cert-*.pem; do echo "$f"; openssl x509 -in "$f" -noout -subject -issuer; done
```

The root certificate is the one whose subject and issuer are the same. The first file is the server certificate, so do not use it. Copy the root certificate to its own file. Replace `<N>` with the number of the file you found:

```bash
cp ~/company-ca/cert-<N>.pem ~/company-ca/company-root.pem
```

If no file has a matching subject and issuer, the network did not send its root certificate. Ask your IT team for it as a PEM file, and save it as `~/company-ca/company-root.pem`.

Add the setting to your shell profile, then open a new terminal. If you use zsh, use `~/.zshrc` instead of `~/.bashrc`:

```bash
echo 'export NODE_EXTRA_CA_CERTS="$HOME/company-ca/company-root.pem"' >> ~/.bashrc
```

If you use Fish, run this command instead:

```fish
set -Ux NODE_EXTRA_CA_CERTS "$HOME/company-ca/company-root.pem"
```

{% endtab %}

{% tab title="Windows" %}
In PowerShell, find the root certificate. Replace `<certificate name>` with the name your IT team gives you:

```powershell
Get-ChildItem Cert:\CurrentUser\Root,Cert:\LocalMachine\Root | Where-Object { $_.Subject -like '*<certificate name>*' } | Format-List Subject,Thumbprint
```

Export it. If it is in the current user's store, use `Cert:\CurrentUser\Root` instead:

```powershell
Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -like '*<certificate name>*' } | Select-Object -First 1 | Export-Certificate -FilePath $env:USERPROFILE\company-root.cer
```

Node.js needs PEM text, so convert the file:

```powershell
certutil -encode $env:USERPROFILE\company-root.cer $env:USERPROFILE\company-root.pem
```

Make the setting permanent for your user, then close PowerShell and open a new window:

```powershell
[Environment]::SetEnvironmentVariable('NODE_EXTRA_CA_CERTS', "$env:USERPROFILE\company-root.pem", 'User')
```

In cmd.exe, use this command instead, then open a new window:

```
setx NODE_EXTRA_CA_CERTS "%USERPROFILE%\company-root.pem"
```

These Windows steps are documented from vendor guidance and have not yet been run end to end.
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Certificate already installed by IT?** Node.js 22.15 or newer can read the operating system's certificate store directly. Set `NODE_OPTIONS=--use-system-ca` instead of `NODE_EXTRA_CA_CERTS`. Node.js 20 does not have this option.
{% endhint %}

#### Step 3: Fix the proxy

Ask your IT team for the proxy URL. Then check your Node.js version:

```bash
node --version
```

Node.js uses the proxy setting below on version 22.21 or newer, and on version 24.0 or newer. Node.js 20 and earlier versions of Node.js 22 ignore it with no error. On those versions, upgrade Node.js first.

{% tabs %}
{% tab title="macOS and Linux" %}
Add both settings to your shell profile, then open a new terminal. Use `~/.bashrc` instead of `~/.zshrc` if you use bash:

```bash
echo 'export NODE_USE_ENV_PROXY=1' >> ~/.zshrc
echo 'export HTTPS_PROXY="<proxy URL>"' >> ~/.zshrc
```

If you use Fish, run these commands instead:

```fish
set -Ux NODE_USE_ENV_PROXY 1
set -Ux HTTPS_PROXY "<proxy URL>"
```

{% endtab %}

{% tab title="Windows" %}
In PowerShell, set both values for your user, then open a new window:

```powershell
[Environment]::SetEnvironmentVariable('NODE_USE_ENV_PROXY', '1', 'User')
[Environment]::SetEnvironmentVariable('HTTPS_PROXY', '<proxy URL>', 'User')
```

In cmd.exe, use `setx NODE_USE_ENV_PROXY 1` and `setx HTTPS_PROXY "<proxy URL>"` instead.

These Windows steps are documented from vendor guidance and have not yet been run end to end.
{% endtab %}
{% endtabs %}

Node.js may print a one-time warning that `EnvHttpProxyAgent` is experimental. This warning is normal.

#### Step 4: Confirm

Open a new terminal, go to the folder where you saved `check.js`, and run the check again:

```bash
node check.js
```

It must print `HTTP 403 {"message":"Forbidden"}`. A `403` with any other text means a proxy or security appliance is blocking the request, so ask your IT team to allow `api.revenium.ai`. Then send a test event with the CLI, for example:

```bash
revenium-codex test --verbose
```

Codex itself is not a Node.js program, so it does not read `NODE_EXTRA_CA_CERTS`. Codex reads the certificate file from `CODEX_CA_CERTIFICATE`, or from `SSL_CERT_FILE` when the first is not set. Set `CODEX_CA_CERTIFICATE` to the same PEM file in the same way as in step 2. Then run one Codex session and confirm its usage appears in Revenium.

**For IT teams:** if you add `api.revenium.ai` to the TLS inspection bypass list, developers do not need step 2.

### Telemetry conflicts with another AI tool

If Codex data is missing or misattributed on a machine that also runs Claude Code or Gemini, a conflicting OTLP environment variable from the other tool is the likely cause. Always launch Codex through a shell that has loaded the Revenium wrapper (restart your terminal after setup) — the wrapper unsets the conflicting variables before Codex runs.

## Command reference

| Command                                              | Description                                  |
| ---------------------------------------------------- | -------------------------------------------- |
| `revenium-codex setup`                               | Interactive setup wizard                     |
| `revenium-codex setup --force`                       | Setup, overwriting existing `[otel]` section |
| `revenium-codex status`                              | Verify connectivity to Revenium              |
| `revenium-codex test --verbose`                      | Send a synthetic test event                  |
| `revenium-codex backfill --since <date> --to <date>` | Import historical session data               |
| `revenium-codex backfill --dry-run`                  | Preview backfill output without sending      |
| `revenium-codex backfill --batch-size <n>`           | Control backfill throughput                  |
| `revenium-codex backfill --sessions-path <path>`     | Custom sessions directory                    |
| `revenium-codex backfill --config-path <path>`       | Custom config.toml location                  |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.revenium.io/track-and-control-costs/analyze-ai-tooling-spend/setup-codex.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
