Skip to main content

Overview

OpenClaw is a self-hosted personal AI assistant. Its gateway ships a built-in diagnostics-otel plugin that exports OpenTelemetry traces and logs — including per–model-call token usage — directly over OTLP/HTTP. By pointing those exporters at Bronto’s ingestion endpoints, every model call your assistant makes lands in Bronto with full token, model, provider, and (optionally) prompt/response context. This page covers the telemetry configuration only. It applies wherever you run the OpenClaw gateway — Docker, a VM, or a managed host — and does not assume any particular cloud.
OpenClaw exports directly to Bronto’s OTLP endpoints. You do not need a separate OpenTelemetry Collector in between, though you can route through one if you already run it.

Prerequisites

  • A running OpenClaw gateway (any host).
  • A Bronto account and an API key with ingestion permissions — see API Keys.
  • Your Bronto region (eu or us), so you target the matching endpoint — see Bronto endpoints.

Enable the diagnostics-otel plugin

The exporter ships as a plugin. Install and enable it on the gateway:
openclaw plugins install clawhub:@openclaw/diagnostics-otel
openclaw plugins enable diagnostics-otel
If you manage configuration as a file, ensure the plugin is allowed and enabled:
{
  "plugins": {
    "allow": ["diagnostics-otel"],
    "entries": {
      "diagnostics-otel": { "enabled": true }
    }
  }
}

Configure export to Bronto

Add a diagnostics.otel block to your OpenClaw configuration. Set the per-signal endpoints (/v1/traces, /v1/logs) explicitly so each signal reaches the right path, and authenticate with the x-bronto-api-key header. OpenClaw’s logs toggle defaults to false, so set "logs": true to send log records alongside traces.
{
  "diagnostics": {
    "enabled": true,
    "otel": {
      "enabled": true,
      "endpoint": "https://ingestion.eu.bronto.io",
      "tracesEndpoint": "https://ingestion.eu.bronto.io/v1/traces",
      "logsEndpoint": "https://ingestion.eu.bronto.io/v1/logs",
      "protocol": "http/protobuf",
      "serviceName": "openclaw-gateway",
      "headers": {
        "x-bronto-api-key": "${BRONTO_API_KEY}",
        "x-bronto-dataset": "openclaw",
        "x-bronto-collection": "openclaw-demo"
      },
      "traces": true,
      "logs": true,
      "sampleRate": 1
    }
  }
}

Endpoints by region

Replace eu with us if your account is in the US region.
RegionTracesLogs
EUhttps://ingestion.eu.bronto.io/v1/traceshttps://ingestion.eu.bronto.io/v1/logs
UShttps://ingestion.us.bronto.io/v1/traceshttps://ingestion.us.bronto.io/v1/logs

Headers

HeaderDescription
x-bronto-api-keyYour Bronto ingestion API key (required)
x-bronto-datasetThe Bronto dataset that telemetry is routed to
x-bronto-collectionGroups related services within the dataset — e.g. openclaw-demo, production

Key settings

KeyNotes
protocolMust be http/protobuf. OpenClaw ignores gRPC.
serviceNameIdentifies the source in Bronto — appears as service.name.
sampleRateRoot-span sampling ratio, 0.01.0. Use 1 to capture every model call.
The example above does not hardcode the API key — it uses ${BRONTO_API_KEY} interpolation so the secret stays out of committed config. OpenClaw resolves environment variables inside any config string and throws at load if the variable is missing, which fails fast instead of starting up unauthenticated. Set BRONTO_API_KEY in the gateway’s environment, or use a SecretRef if your deployment manages secrets that way.

Set the GenAI semantic-convention environment variable

OpenClaw only emits the stable GenAI semantic-convention attributes when you opt in. This is an environment variable — it cannot be set in openclaw.json, so it applies even if you configured everything else through the config file. Set it on the gateway:
export OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
Without it, spans carry OpenClaw’s own attributes (openclaw.provider, openclaw.model, openclaw.tokens.*) but omit the standard gen_ai.* attributes such as gen_ai.request.model, gen_ai.provider.name, and gen_ai.usage.input_tokens / gen_ai.usage.output_tokens. Set it if you want the GenAI-convention fields, which is what most LLM-observability tooling and Bronto queries key off.

Capture prompt and response content (optional)

By default OpenClaw exports spans with bounded identifiers only (model, provider, token counts) and no prompt or response text. For richer LLM observability — debugging a bad answer, auditing tool calls — enable captureContent. Each sub-option is independent so you can capture only what you need:
{
  "diagnostics": {
    "otel": {
      "captureContent": {
        "enabled": true,
        "inputMessages": true,
        "outputMessages": true,
        "toolInputs": true,
        "toolOutputs": true,
        "systemPrompt": false,
        "toolDefinitions": false
      }
    }
  }
}
Sub-optionCaptures
inputMessagesUser prompt text
outputMessagesModel response text
toolInputsTool argument payloads
toolOutputsTool result payloads
systemPromptThe assembled system/developer prompt
toolDefinitionsTool names, descriptions, and schemas

Configure with environment variables

If you prefer environment variables (for example, in a container), OpenClaw honors the standard OTLP variables, which override the corresponding config keys:
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://ingestion.eu.bronto.io/v1/traces"
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="https://ingestion.eu.bronto.io/v1/logs"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_SERVICE_NAME="openclaw-gateway"
export OTEL_EXPORTER_OTLP_HEADERS="x-bronto-api-key=${BRONTO_API_KEY},x-bronto-dataset=openclaw,x-bronto-collection=openclaw-demo"
The GenAI semantic-convention opt-in described above is an environment variable in all cases — set it here too.

What gets sent to Bronto

Once configured, OpenClaw emits: Traces — one span per model call and tool execution, following the OpenTelemetry GenAI semantic conventions:
SpanKey attributes
openclaw.model.usagegen_ai.usage.*, openclaw.tokens.*
openclaw.model.callgen_ai.request.model, gen_ai.operation.name
openclaw.tool.executiongen_ai.tool.name
Common attributes carried across spans include openclaw.provider, openclaw.model, openclaw.agent, openclaw.channel, and — on failures — openclaw.errorCategory and openclaw.failureKind. Logs — the gateway’s log records, when logs is enabled.

Verify in Bronto

After restarting the gateway with the new configuration, generate some activity (send the assistant a message), then check Bronto. Telemetry is keyed by the service.name you set (openclaw-gateway):
  • Traces — open the Traces view. Look for the openclaw.model.call and openclaw.model.usage spans. A working export shows openclaw.tokens.total on the usage span, and — with the GenAI semantic-convention env var set — gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, and gen_ai.request.model. Spans are not log events, so use the Traces UI rather than log search to inspect them.
  • Logs — open Search and filter to the dataset and collection from your headers (openclaw / openclaw-demo).
Don’t rely on the gateway logs to confirm export is working. OpenClaw only logs a logs exporter enabled line — it does not log a traces (or metrics) exporter line, and it does not log export failures. “No errors in the logs” is not evidence that data reached Bronto; confirm by finding the spans above in the Traces UI.

Troubleshooting

No data in Bronto. Confirm the per-signal endpoints are set (not just the base endpoint) and that protocol is http/protobuf — OpenClaw ignores gRPC. Traces arrive but no logs. OpenClaw’s logs toggle defaults to false. Set "logs": true (or OTEL_EXPORTER_OTLP_LOGS_ENDPOINT with logs enabled). Spans arrive but gen_ai.* attributes are missing. Set the OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental environment variable — without it OpenClaw emits only its own openclaw.* attributes. See Set the GenAI semantic-convention environment variable. No prompt/response content on spans. This is expected unless you enable captureContent — see Capture prompt and response content. Plugin not exporting. Verify diagnostics-otel is in plugins.allow and enabled, and that diagnostics.enabled and diagnostics.otel.enabled are both true.