Backends overview
hermes-otel exports plain OTLP (OpenTelemetry's wire protocol) over HTTP, or over gRPC with the generic otlp type, so any OTLP-compatible backend should work. The ones below ship with first-class support, docker-compose files, and (where relevant) smoke-test coverage.
Supported today
| Backend | Signals | Deployment | Account / cost |
|---|---|---|---|
| Phoenix | Traces only | Local (single container) · Arize AX cloud | OSS, no account · commercial cloud |
| Langfuse | Traces | Local (docker compose) · Cloud | OSS, no account · free tier + paid |
| LangSmith | Traces | Cloud only (self-host = enterprise) | Free personal tier · paid tiers |
| SigNoz | Traces + metrics + logs | Local (docker compose) · Cloud | OSS, no account · free tier + paid cloud |
| Jaeger | Traces | Local (single container) | OSS, no account needed |
| Zipkin | Traces | Local (single container, the zipkin-otel image) | OSS (Apache-2.0), no account |
| GreptimeDB | Traces + metrics + logs | Local (single container) · Helm · GreptimeCloud | OSS (Apache-2.0), no account |
| ClickStack (HyperDX) | Traces + metrics + logs | Local (one all-in-one container) · upstream compose · Helm · ClickHouse Cloud | OSS (MIT), local account on first run |
| VictoriaMetrics family | Traces + metrics + logs | Local (three single-binary containers) · Helm · VictoriaMetrics Cloud | OSS (Apache-2.0), no account |
| Aspire Dashboard | Traces + metrics + logs | Local (single container) | OSS (MIT), no account |
| Gigapipe (qryn) | Traces + metrics + logs | Local (Gigapipe + ClickHouse) · Gigapipe Cloud | OSS (AGPL-3.0), no account |
| Agenta | Traces | Local (docker compose, eleven containers) · Agenta Cloud (US / EU) | OSS (MIT), local account · free cloud tier |
| Grafana Tempo | Traces | Local (docker compose) · Grafana Cloud | OSS, no account · free tier + paid cloud |
| Grafana LGTM | Traces + metrics + logs | Local (single container) | OSS, no account |
| Uptrace | Traces + metrics + logs | Local (docker compose) · Self-hosted | OSS · premium license for HA features |
| OpenObserve | Traces + metrics + logs | Local (single container) · Self-hosted HA | OSS, no account |
| Parseable | Traces + metrics + logs | Self-hosted · Cloud | OSS · paid cloud |
| Honeycomb | Traces + metrics + logs | Cloud (US / EU) | Generous free tier · paid plans |
| W&B Weave | Traces | W&B Cloud · Dedicated Cloud · Self-Managed | W&B account |
| Elastic | Traces + metrics + logs | Elastic Cloud (mOTLP) · self-hosted EDOT Collector | Elastic license / cloud plan |
Azure Monitor (via the Collector, generic otlp) | Traces + metrics + logs | Azure subscription + the repo's Collector container | Azure pricing; documented, not verified |
| OpenLIT | Traces + metrics + logs | Local (docker compose, 2 containers) · Helm | OSS (Apache-2.0), no account |
| MLflow | Traces | Local (docker compose, 1 container) · Helm · Databricks | OSS (Apache-2.0), no account |
| Comet Opik | Traces | Local (docker compose, 7 containers) · Helm · Comet cloud | OSS (Apache-2.0) · free cloud tier |
| Laminar | Traces + logs | Local (docker compose, 5 containers) · Helm · Laminar cloud | OSS (Apache-2.0) · free cloud tier |
| LangWatch | Traces + metrics + logs | Local (docker compose, 5 containers) · Helm · LangWatch cloud | OSS (Apache-2.0) · free cloud tier |
| Latitude | Traces | Local (docker compose, 13 containers) · Helm · Latitude cloud | OSS (MIT) · free cloud tier |
telemetry.dev (via generic otlp) | Traces + metrics + logs | Cloud | Free tier + paid plans |
| Generic OTLP | Depends on collector | Anywhere | — |
Quick picks
"I just want to see a trace, right now, on my laptop" → Phoenix — one container, open the UI on port 6006, done. Or the Aspire Dashboard — one container, all three signals, a GenAI visualizer, and the plugin dashboard reads traces and logs back.
"I want pretty LLM-specific UI and I'm fine running a stack" → Langfuse — polished UI for LLM traces, free cloud tier, robust self-host.
"I want traces and the token/tool/cost metrics dashboard" → SigNoz, LGTM or OpenObserve — they accept OTLP metrics as well as traces (Phoenix does not).
"I want the Grafana APIs without running Grafana's stores" → Gigapipe — OTLP in, the Tempo, Prometheus and Loki APIs out of one port on ClickHouse; the plugin reads it with its LGTM adapters.
"I run VictoriaMetrics and want traces and logs in the same family" → VictoriaTraces + VictoriaMetrics + VictoriaLogs — one entry, three stores; the dashboard reads them through the Jaeger, Prometheus and LogsQL APIs.
"I want ClickHouse's own observability stack with a search UI" → ClickStack — HyperDX on ClickHouse in one container, traces + metrics + logs in the standard OTel tables; the dashboard adapter reads them straight from ClickHouse.
"I want all three signals in one open-source database I can query with SQL"
→ GreptimeDB — one container, OTLP in under /v1/otlp, SQL, PromQL and a Jaeger-compatible API out; the dashboard adapter reads all three signals.
"I want all three signals — traces, metrics, AND logs — in Grafana, in one container"
→ Grafana LGTM — grafana/otel-lgtm bundles Grafana + Tempo + Loki + Mimir + a collector. Turn on logs: {capture: true} and you get trace-id-correlated logs out of the box.
"I'm already on LangChain / LangSmith" → LangSmith — free personal tier, zero extra infra.
"Standard distributed tracing stack, no LLM-specific UI needed" → Jaeger, Zipkin or Grafana Tempo — all three are traces-only; pair with Prometheus if you need metrics. Zipkin is the lightest read API of the three and the dashboard adapter reads it.
"I want Claude Code, Cursor or Hermes itself to search the traces over MCP"
→ Jaeger (v1) or Grafana Tempo, read by Traceloop's opentelemetry-mcp server; verified setup and caveats in Query your traces over MCP.
"I want a cloud backend with a generous free tier and all three signals"
→ Honeycomb — OTLP-native; set OTEL_HONEYCOMB_API_KEY and a region.
"I want W&B's Agents and Traces UI for Hermes runs"
→ W&B Weave — direct OTLP trace ingest with OTEL_WEAVE_API_KEY, wandb.entity, and wandb.project.
"I want Hermes agent runs plus traces, metrics, and logs in Parseable" → Parseable — direct OTLP ingest into three datasets, with Agent Observability and a ready-made dashboard.
"I want a hosted backend purpose-built for LLM/agent telemetry, gen_ai.*-native"
→ telemetry.dev — OTLP ingest with a single Authorization: Bearer header, via the generic otlp type.
"I want an OTel-native LLM UI with all three signals, self-hosted and light"
→ OpenLIT — two containers, gen_ai.*-aware views, traces + metrics + logs on the standard /v1/* paths.
"We already run MLflow for experiments" → MLflow — traces land in an experiment next to your runs, with MLflow's own token and cost roll-ups.
"I want the richest LLM-trace view of the self-hosted batch: threads, span types, cost per call"
→ Comet Opik — maps both gen_ai.* and llm.* conventions; thread_id is the Hermes session.
"An agent-focused trace UI that also keeps the agent's log lines" → Laminar — span types, tokens and cost per call, plus log records next to the trace; metrics are off because Laminar drops them.
"An open-source LLMOps platform that reads both conventions and queries back"
→ Agenta — OTLP traces with a project key; span types, token roll-ups and sessions computed server-side; the dashboard adapter reads POST /api/spans/query.
"An LLM platform with all three signals and an evaluation workflow"
→ LangWatch — traces, metrics and logs under one /api/otel prefix; thread id = the Hermes session.
"Our observability is already Elastic (self-hosted or Elastic Cloud)"
→ Elastic — one type: elastic entry covers the managed OTLP endpoint (ApiKey auth) and a self-hosted EDOT Collector (no key needed).
"My company already has an OTel collector / New Relic / Datadog" → Generic OTLP — point at its ingest endpoint and it just works.
"We are on Azure / Application Insights"
→ Azure Monitor — no static-header OTLP endpoint exists, so the repo's Collector with COLLECTOR_TARGET=azuremonitor sends with the connection string; type: otlp at :4448.
"I want several of the above simultaneously" → Multi-backend fan-out — same spans, parallel, non-blocking.
Signal support
Backends differ in which OTel signals they accept. Each backend type turns off, by default, the signals its backend can't take, so you don't need to configure anything. An explicit traces / metrics / logs on the entry still wins.
| Backend | Traces | Metrics | Logs |
|---|---|---|---|
| Phoenix | ✅ | ❌ (rejects /v1/metrics; the plugin defaults metrics: false) | ❌ |
| Langfuse | ✅ | ❌ | ❌ |
| LangSmith | ✅ | ❌ | ❌ |
| SigNoz | ✅ | ✅ | ✅ |
| Jaeger | ✅ | ❌ | ❌ |
| Zipkin | ✅ | ❌ (/v1/metrics is 404) | ❌ (/v1/logs answers 202 but stores a record only as a span annotation; off by default) |
| GreptimeDB | ✅ | ✅ (no exponential histograms) | ✅ |
| ClickStack | ✅ | ✅ | ✅ |
| VictoriaMetrics family | ✅ | ✅ (when metrics_endpoint names VictoriaMetrics) | ✅ (when logs_endpoint names VictoriaLogs) |
| Aspire Dashboard | ✅ | ✅ (no exponential histograms) | ✅ |
| Gigapipe | ✅ | ✅ (cumulative only) | ✅ |
| Agenta | ✅ | ❌ | ❌ |
| Grafana Tempo | ✅ | ❌ | ❌ |
| Grafana LGTM | ✅ | ✅ | ✅ |
| Uptrace | ✅ | ✅ | ✅ |
| OpenObserve | ✅ | ✅ | ✅ |
| Parseable | ✅ | ✅ | ✅ |
| Honeycomb | ✅ | ✅ | ✅ |
| W&B Weave | ✅ | ❌ | ❌ |
| Elastic | ✅ | ✅ | ✅ |
| Azure Monitor (via the Collector) | ✅ | ✅ (converted to delta in the Collector) | ✅ |
| OpenLIT | ✅ | ✅ | ✅ |
| MLflow | ✅ | ❌ | ❌ |
| Comet Opik | ✅ | ❌ | ❌ |
| Laminar | ✅ | ❌ (accepted and dropped; off by default) | ✅ |
| LangWatch | ✅ | ✅ | ✅ |
| Latitude | ✅ | ❌ | ❌ |
| telemetry.dev | ✅ | ✅ | ✅ |
| Generic OTLP | ✅ | ✅ on by default; set metrics: false if the collector rejects it | ✅ on by default; set logs: false if the collector rejects it |
If you care about token / tool / cost metrics on a traces-only backend, pair it with a Prometheus-compatible sink or fan out to SigNoz / LGTM / OpenObserve alongside. See OTel logs for the logs pipeline.
Metrics and your backend
Two metric settings depend on the backend (since 1.15; details on the metrics reference):
| Backend | Temporality it wants | Preset | Exponential histograms |
|---|---|---|---|
| Grafana LGTM, Tempo-side Prometheus, Mimir | cumulative (delta is dropped unless otlp-deltatocumulative is on) | cumulative (default) | Prometheus 3.8+ native histograms; Mimir only with native-histogram ingestion enabled |
| OpenObserve | cumulative works; delta handling undocumented | cumulative (default) | not documented |
| ClickStack | either: the ClickHouse exporter stores every point as sent | cumulative (default) | stored (otel_metrics_exponential_histogram) |
| VictoriaMetrics | cumulative natively; delta stored as-is since v1.132 (query with sum_over_time) | cumulative (default) | converted to VictoriaMetrics vmrange histograms |
| Gigapipe | cumulative only: delta points are rejected one by one (partial_success) | cumulative (default) | converted to _bucket / _sum / _count |
| Aspire Dashboard | either (stored as sent) | cumulative (default) | rejected ("is not supported"); keep metrics_histogram: explicit |
| GreptimeDB | either: stores cumulative and delta points as sent | cumulative (default) | rejected (ExponentialHistogram is not supported yet); keep metrics_histogram: explicit |
| SigNoz | recommends delta; exponential histograms are delta-only and self-hosted-only | delta | self-hosted only |
| Uptrace | prefers delta, converts cumulative | delta | recommended |
| Honeycomb | either | cumulative (default) | not verified |
Parseable, generic otlp | depends on the collector behind it | cumulative (default) | depends |
| Elastic | delta required (ES does not handle cumulative histograms) | delta | accepted |
| Azure Monitor (via the Collector) | delta required for the Application Insights experiences (Microsoft's statement); the azuremonitor target runs cumulative_to_delta | cumulative (default; the Collector converts) | required by the same statement; not converted by the target, metrics_histogram: exponential is global |
| OpenLIT | cumulative stored as-is (verified) | cumulative (default) | stored (exponential histogram type) |
Datadog, New Relic, Logfire (via generic otlp today, explicit types tracked in #232) | delta required (Datadog rejects cumulative sums; Logfire dashboards stay empty on cumulative; New Relic prefers delta) | set metrics_temporality: delta on the entry | Datadog and New Relic accept them |
Override per entry with metrics_temporality: cumulative | delta, or for every backend with the top-level metrics_temporality. Backends that total a trace by summing every span's gen_ai.usage.* (Opik, LangWatch) are sent the agent root without its token roll-up (root_usage: false, the preset for those two types; true elsewhere), so their trace totals equal the sum of the api.* spans while Phoenix, Langfuse and the rest keep the roll-up on the root. metrics_histogram: exponential switches every backend to base-2 exponential histograms, so use it only when all of them accept those.
Short-lived runs. hermes -z exports metrics once, when it exits. A single cumulative point from a fresh process counts as zero on Datadog and New Relic (they treat the first point as a baseline) and goes stale after five minutes on Prometheus; the same run exported as delta counts in full on every delta-capable backend. Long-lived gateways are unaffected either way.
Selecting a single backend
Single-backend selection is env-var-driven. First match wins:
OTEL_LANGSMITH_API_KEY(orOTEL_LANGSMITH_ENDPOINT) set → LangSmith- Langfuse credentials + at least one
OTEL_LANGFUSE_*variable (OTEL_LANGFUSE_PUBLIC_API_KEY,OTEL_LANGFUSE_SECRET_API_KEYorOTEL_LANGFUSE_ENDPOINT) → Langfuse OTEL_SIGNOZ_ENDPOINTset → SigNozOTEL_UPTRACE_ENDPOINT+ DSN set → UptraceOTEL_OPENOBSERVE_ENDPOINT+ credentials set → OpenObserveOTEL_PARSEABLE_ENDPOINT+OTEL_PARSEABLE_API_KEY(orPARSEABLE_API_KEY) set → ParseableOTEL_WEAVE_API_KEY(orOTEL_WEAVE_ENDPOINT/OTEL_WEAVE_BASE_URL) +WANDB_ENTITY+WANDB_PROJECTset → W&B WeaveOTEL_HONEYCOMB_API_KEY(orOTEL_HONEYCOMB_ENDPOINT) set → HoneycombOTEL_ELASTIC_ENDPOINTset → Elastic (OTEL_ELASTIC_API_KEYoptional: a local EDOT Collector needs none, and a key alone never opts in because Elastic has no default host)OTEL_OPENLIT_ENDPOINTset → OpenLIT (OTEL_OPENLIT_API_KEYoptional, same rule)OTEL_MLFLOW_ENDPOINTset → MLflow (MLFLOW_EXPERIMENT_IDoptional, default0)OTEL_OPIK_API_KEY(cloud, withOPIK_WORKSPACE) orOTEL_OPIK_ENDPOINTset → Comet OpikOTEL_LAMINAR_API_KEYset (cloud, or withOTEL_LAMINAR_ENDPOINT) → LaminarOTEL_LANGWATCH_API_KEYset (cloud, or withOTEL_LANGWATCH_ENDPOINT) → LangWatchOTEL_LATITUDE_API_KEY+LATITUDE_PROJECTset (cloud, or withOTEL_LATITUDE_ENDPOINT) → LatitudeOTEL_AGENTA_API_KEYset (cloud, or withOTEL_AGENTA_ENDPOINT) → AgentaOTEL_CLICKSTACK_ENDPOINT+OTEL_CLICKSTACK_API_KEY(orHYPERDX_API_KEY) set → ClickStackOTEL_GREPTIME_ENDPOINTset → GreptimeDB (OTEL_GREPTIME_DB,OTEL_GREPTIME_USER/OTEL_GREPTIME_PASSWORDoptional)OTEL_VICTORIA_ENDPOINTset → VictoriaTraces (OTEL_VICTORIA_METRICS_ENDPOINT/OTEL_VICTORIA_LOGS_ENDPOINTswitch metrics and logs on)OTEL_ASPIRE_ENDPOINTset → Aspire Dashboard (OTEL_ASPIRE_API_KEYoptional)OTEL_GIGAPIPE_ENDPOINTset → Gigapipe (OTEL_GIGAPIPE_USER/OTEL_GIGAPIPE_PASSWORDoptional)OTEL_JAEGER_ENDPOINTset → JaegerOTEL_ZIPKIN_ENDPOINTset → ZipkinOTEL_TEMPO_ENDPOINTset → TempoOTEL_PHOENIX_ENDPOINTset → Phoenix
Vendor SDK variables (LANGSMITH_API_KEY, LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY, WANDB_API_KEY, HONEYCOMB_API_KEY, ELASTIC_API_KEY, OPENLIT_API_KEY, MLFLOW_TRACKING_TOKEN, OPIK_API_KEY, LMNR_PROJECT_API_KEY, LANGWATCH_API_KEY, LATITUDE_API_KEY, HYPERDX_API_KEY, AGENTA_API_KEY) only fill in credentials. On their own they never switch export on, because they are often set for other tools and Hermes loads $HERMES_HOME/.env into the process; one plugin-namespaced OTEL_* variable is the explicit opt-in. When such credentials are present without the opt-in, the startup log says which OTEL_* variable would enable export, and the dashboard's OTel → Settings → Environment view shows the same notice.
Setting backends: in hermes_otel.yaml overrides the env-var flow entirely — see Multi-backend fan-out.
What each backend does differently
Every one of these speaks OTLP, and every one of them differs in where it listens, which header carries the key, which signals it stores, which metric temporality it wants, how it totals tokens over a trace, what it truncates, and which API gives the data back. Backend quirks is the per-category comparison and lists, per backend, what the plugin does about each difference. In the repo the same catalog is docker-compose/QUIRKS.md.
Running one locally
Every self-hostable backend above, plus the candidates tracked in #232, has its own folder under docker-compose/ in the repo: docker compose -f docker-compose/<name>/docker-compose.yaml up -d, and down -v to remove it with its data. Each folder has a README (why pick it, logins, the backends: snippet, verification query, caveats), and docker-compose/README.md is the manual: the comparison table, the port map, disk/memory budgets and the test loop.
Backends without an explicit type: yet are driven through the generic otlp type; each was verified end to end on 2026-10-05 with hermes-otel 1.19.0 (OpenLIT, MLflow, Opik, Laminar, LangWatch and Latitude have explicit types since 1.23):
| Backend | Compose file | Stored from a Hermes turn | Plugin config |
|---|---|---|---|
| OpenLIT (#222) | openlit/ | traces + metrics + logs | type: openlit, http://localhost:4338 (explicit type since 1.23) |
| MLflow (#221) | mlflow/ | traces (with MLflow's own token and cost roll-ups) | type: mlflow, http://localhost:5001 (explicit type since 1.23) |
| Comet Opik (#220) | opik/ | traces (threads, span types, cost) | type: opik, http://localhost:5173 (explicit type since 1.23) |
| Laminar (#223) | laminar/ | traces + logs; metrics accepted and dropped | type: laminar, http://localhost:8100, api_key_env (explicit type since 1.23) |
| LangWatch (#229) | langwatch/ | traces + metrics + logs | type: langwatch, http://localhost:5560, api_key_env (explicit type since 1.23) |
| Langtrace (#224) | langtrace/ | traces (string and int attributes only) | type: otlp, http://localhost:3040/api/trace, header x-api-key, metrics: false, logs: false |
| Sigiro (#71) | sigiro/ | traces + metrics + logs | type: otlp, http://localhost:4378/v1/traces |
| OpenTelemetry Collector (#368) | collector/ | traces + metrics + logs, printed (debug) or forwarded (otlphttp, verified into the viewer); Azure Monitor / AWS / Google Cloud targets documented | type: otlp, http://localhost:4448/v1/traces; COLLECTOR_TARGET picks the destination |
| otel-desktop-viewer (#367) | otel-desktop-viewer/ | traces + metrics + logs (5 spans, 27 log records, 13 metric names from one turn) | type: otlp, http://localhost:4428/v1/traces; UI :3070, JSON-RPC POST /rpc. otel-tui is the terminal sibling: a docker run line in the same README, :4438 |
| Maple Local (#49) | maple/ | traces + metrics + logs | type: otlp, http://localhost:4388/v1/traces |
| Parseable OSS (#238) | parseable/ | traces + metrics + logs, through the bundled collector | type: otlp, http://localhost:4348/v1/traces |
| Zipkin (#364) | zipkin/ | traces (7 spans from one turn; every attribute a string tag) | type: zipkin, http://localhost:9411 (the zipkin-otel image; stock Zipkin has no OTLP) |
| Agenta (#371) | agenta/ | traces (7 spans with Agenta's token roll-ups from one turn) | type: agenta, http://localhost:3060, api_key_env (key from agenta/mint-api-key.sh) |
| Gigapipe (#370) | gigapipe/ | traces + metrics + logs (7 spans, 28 log lines, 27 metric names from one turn) | type: gigapipe, http://localhost:3110 |
| Aspire Dashboard (#369) | aspire/ | traces + metrics + logs (7 spans, 28 log rows from one turn; metrics in the UI only) | type: aspire, http://localhost:4418, query_port: 18888 |
| VictoriaTraces + VictoriaLogs + VictoriaMetrics (#366) | victoria/ | traces + metrics + logs (7 spans, 28 log rows, 27 metric names from one turn) | type: victoria, endpoint :10428 + metrics_endpoint :8428 + logs_endpoint :9428 |
| ClickStack (#365) | clickstack/ | traces + metrics + logs (7 spans, 28 log rows, 13 metric names from one turn) | type: clickstack, http://localhost:4408, api_key_env (key from clickstack/mint-api-key.sh) |
| GreptimeDB (#363) | greptime/ | traces + metrics + logs (7 spans, 28 log rows, 27 metric tables from one turn) | type: greptime, http://localhost:4398 (the trace pipeline header on traces only) |
| Latitude (#230) | latitude/ | traces (13 containers, ~15 GB of images) | type: latitude, http://localhost:3002, api_key_env + project (explicit type since 1.23) |
Elastic (elastic/: Elasticsearch + Kibana + EDOT Collector, type: elastic) was added on 2026-10-07 and verified with hermes-otel 1.21.0. Two of these are not open source: Sigiro publishes only a binary image, and Maple is source-available under FSL-1.1. Jaeger v2 (jaeger-v2/) and Langfuse v4 (LANGFUSE_VERSION=4) have their own stacks so the read-side issues #245 and #246 can be reproduced locally.
Planned
These are OTLP-compatible and should work today with the generic OTLP backend — first-class docs, docker-compose files, and smoke tests are on the roadmap:
File an issue if you've tried one of these and hit friction — we'll prioritise.