OpenTelemetry
Emit Vision accepts OpenTelemetry data over OTLP/HTTP JSON. If your Node.js app already uses OpenTelemetry instrumentation, you can point your exporters at Emit Vision without replacing your existing setup.
New to Emit Vision? Use the native @emit-vision/sdk-node instead.
OpenTelemetry is the compatibility path for teams that already have OTel wired
up and don't want to change their instrumentation layer.
What's supported
| Supported | Not supported |
|---|---|
OTLP/HTTP JSON logs (POST /otlp/v1/logs) | OTLP Protobuf |
OTLP/HTTP JSON traces (POST /otlp/v1/traces) | OTLP/gRPC |
| Bearer-token auth with your Emit Vision API key | Metrics ingestion |
| Gantt / waterfall trace visualization |
Setup
Install the OpenTelemetry Node SDK and exporters:
npm install @opentelemetry/sdk-node \
@opentelemetry/exporter-logs-otlp-http \
@opentelemetry/exporter-trace-otlp-http \
@opentelemetry/sdk-logs \
@opentelemetry/sdk-trace-base \
@opentelemetry/auto-instrumentations-nodeConfigure and start the SDK:
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { SimpleLogRecordProcessor } from "@opentelemetry/sdk-logs";
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
const apiKey =
process.env.EMIT_VISION_API_KEY ??
"evk_local_development_seed_key_000000000000";
const endpoint = process.env.EMIT_VISION_ENDPOINT ?? "http://localhost:4301";
const baseUrl = `${endpoint}/otlp/v1`;
const headers = { Authorization: `Bearer ${apiKey}` };
const sdk = new NodeSDK({
logRecordProcessors: [
new SimpleLogRecordProcessor(
new OTLPLogExporter({ url: `${baseUrl}/logs`, headers }),
),
],
spanProcessors: [
new SimpleSpanProcessor(
new OTLPTraceExporter({ url: `${baseUrl}/traces`, headers }),
),
],
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();Drop the trace exporter if you only want logs, or the log exporter if you only want traces.
Field mapping
OTLP data is normalized into Emit Vision's event envelope. Some fidelity is lost intentionally so traces and logs reuse the same dashboard model.
| OTLP field | Emit Vision field | Notes |
|---|---|---|
resource.attributes["service.name"] | tags.service | Stored on all logs and spans |
resource.attributes["service.version"] | release | Filters by deployed version |
Log body | name or properties.body | String body → event name; structured → properties |
Log severityText | tags.severity | Used for visual emphasis |
Log/span traceId | context.traceId | Preserved for correlation |
Log/span spanId | context.spanId | Preserved |
Span name | name | Becomes the dashboard event name |
Span startTimeUnixNano | timestamp | Span start time → event timestamp |
| Span duration | properties.durationMs | Calculated from start/end |
| Span attributes | properties | Sensitive keys are scrubbed |
Span status.code === ERROR | type: "error" | Error spans appear in the errors flow |
Span status.message | error.message | Used as error message when present |
Limitations
- Parent-child span relationships are stored as metadata but Emit Vision does not render a waterfall or Gantt chart. Spans appear as flat events.
- Metrics are not ingested.
- Sampling stays within your OTel SDK — Emit Vision does not add a separate sampling layer.
- Browser OTLP is not supported; use
@emit-vision/sdk-jsfor browser apps.
When to use OpenTelemetry vs the native SDK
| Use case | Recommendation |
|---|---|
| New project, minimal setup | Native @emit-vision/sdk-node |
| Existing OTel instrumentation you don't want to replace | OpenTelemetry path |
| Need session timelines, custom events, or feature flags | Native SDK |
| Want to keep your existing exporter wiring | OpenTelemetry path |
For new projects, start with the native SDK — it's fewer packages and the integration is more direct. Point OTel at Emit Vision only when you already have OTel and don't want to maintain two instrumentation stacks.