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

# Claude Code OTLP monitoring

> Send Claude Code OpenTelemetry logs to Runlayer without installing hooks

Claude Code can export OpenTelemetry logs straight to Runlayer. Use this setup
for fleets where you cannot install the Runlayer hooks: CI runners, ephemeral
devcontainers, managed images, or any environment you configure with environment
variables instead of per-machine setup.

Runlayer accepts Claude Code <Tooltip tip="OpenTelemetry Protocol">OTLP</Tooltip> logs at:

```text theme={null}
https://<your-tenant>.runlayer.com/api/v1/hooks/claude-code/otlp/v1/logs
```

<Note>
  Hooks remain the richer integration: they run inline and can block a tool call,
  while OTLP is observe-only and arrives after the fact. Enable OTLP where hooks
  cannot run. Use one capture path per machine. See
  [Choosing hooks or OTLP](#choosing-hooks-or-otlp).
</Note>

## Requirements

* Claude Code with telemetry enabled (`CLAUDE_CODE_ENABLE_TELEMETRY=1`)
* A Runlayer organization API key with the **Shadow AI Scan** role
* Full session scanning enabled for **Claude Code** in Runlayer

## Create the Runlayer API key

<Steps>
  <Step title="Open Organization API keys">
    In Runlayer, go to **Settings -> Organization API keys**.
  </Step>

  <Step title="Create a scoped key">
    Click **Create Organization API Key**, give it a name such as
    `Claude Code OTLP`, and select **Shadow AI Scan**.
  </Step>

  <Step title="Copy the key">
    Copy the generated `rl_org_...` value. Claude Code sends this key in the OTLP
    exporter header, and Runlayer rejects user API keys or org keys without the
    **Shadow AI Scan** role.
  </Step>
</Steps>

## Enable Claude Code in Runlayer

<Steps>
  <Step title="Open Agent session monitoring">
    In Runlayer, go to **Settings → Agent session monitoring**.
  </Step>

  <Step title="Enable the API">
    Turn on **Full session scanning APIs**.
  </Step>

  <Step title="Enable Claude Code">
    Under **Hook clients**, turn on **Claude Code**, then save the settings.
  </Step>
</Steps>

## Configure Claude Code

Set these environment variables wherever Claude Code runs. That can be a managed
profile, a CI job definition, or a container image:

```bash theme={null}
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://<your-tenant>.runlayer.com/api/v1/hooks/claude-code/otlp/v1/logs
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer rl_org_..."
```

| Variable                           | Value                                               |
| ---------------------------------- | --------------------------------------------------- |
| `CLAUDE_CODE_ENABLE_TELEMETRY`     | `1` (required; nothing is exported without it)      |
| `OTEL_LOGS_EXPORTER`               | `otlp`. Sessions are assembled from the logs signal |
| `OTEL_EXPORTER_OTLP_PROTOCOL`      | `http/protobuf` recommended; `http/json` also works |
| `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | The Runlayer logs endpoint above                    |
| `OTEL_EXPORTER_OTLP_HEADERS`       | `Authorization=Bearer rl_org_...`                   |

Use the logs-specific `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` rather than the shared
`OTEL_EXPORTER_OTLP_ENDPOINT` so that only the logs signal is routed to Runlayer
and any existing metrics or traces destination is left untouched. If you do point
the shared endpoint at Runlayer, metrics are accepted and acknowledged but not
ingested. Sessions come from logs only.

### Capturing prompts and tool inputs

By default Claude Code redacts prompt text and tool parameters. Session
timelines are far more useful with them, so opt in where your policy allows:

```bash theme={null}
export OTEL_LOG_USER_PROMPTS=1
export OTEL_LOG_TOOL_DETAILS=1
```

Without `OTEL_LOG_TOOL_DETAILS`, Runlayer still records which tool ran and
whether it was accepted or rejected, but not the arguments it ran with.

## Choosing hooks or OTLP

Enable one capture path per machine. A machine running both the Runlayer hooks
and OTLP export reports each tool call twice: Runlayer de-duplicates events that
share a tool-use id, but hook and telemetry timestamps differ, so some
duplicates survive into the timeline.

|                                  | Hooks            | OTLP                                  |
| -------------------------------- | ---------------- | ------------------------------------- |
| Can block a tool call            | Yes              | No, observe-only                      |
| Needs per-machine install        | Yes              | No, environment variables only        |
| Captures prompts and tool inputs | Yes              | Only with the opt-in variables above  |
| Session close                    | Real session end | Closed automatically after inactivity |

## Verify in Runlayer

1. Start a new Claude Code session and submit a prompt.
2. Open **Sessions** in Runlayer.
3. Filter by client **Claude Code**.

You should see prompts, tool decisions, tool results, API requests, and API
errors in the session timeline. Claude Code's OTLP logs carry no session-end
event, so Runlayer closes these sessions automatically once they stop sending
activity.

## Troubleshooting

<AccordionGroup>
  <Accordion title="No Claude Code sessions appear">
    * Confirm `CLAUDE_CODE_ENABLE_TELEMETRY=1` is set in the environment that
      actually launches Claude Code.
    * Confirm **Full session scanning APIs** is on.
    * Confirm **Claude Code** is enabled under **Hook clients**. When it is off,
      Runlayer still returns success to the exporter and drops the batch, so the
      exporter reports no errors.
    * Confirm the endpoint path ends in `/api/v1/hooks/claude-code/otlp/v1/logs`.
    * Restart Claude Code after changing environment variables.
  </Accordion>

  <Accordion title="Runlayer returns 403">
    Use an organization API key with the **Shadow AI Scan** role. Personal user
    API keys and org keys without that role are rejected for OTLP ingestion.
  </Accordion>

  <Accordion title="Runlayer returns 404">
    The client segment in the URL is not one Runlayer ingests OTLP for. Check the
    spelling of `claude-code` in the endpoint path.
  </Accordion>

  <Accordion title="Prompts appear empty">
    Claude Code redacts prompt text unless `OTEL_LOG_USER_PROMPTS=1` is set, and
    tool parameters unless `OTEL_LOG_TOOL_DETAILS=1` is set.
  </Accordion>
</AccordionGroup>
