OpenTelemetry to Zipkin Transformation

Status: Stable

This document defines the transformation between OpenTelemetry and Zipkin Spans. The generic transformation rules specified here also apply. If a particular generic transformation rule and the rule in this document contradict then the rule in this document MUST be used.

Zipkin’s v2 API is defined in the zipkin.proto


The following table summarizes the major transformations between OpenTelemetry and Zipkin.

OpenTelemetry Zipkin Notes
Span.TraceId Span.trace_id
Span.ParentId Span.parent_id
Span.TraceState TBD TBD
Span.Kind Span.kind See SpanKind for values mapping
Span.StartTime Span.timestamp See Unit of time
Span.EndTime Span.duration Duration is calculated based on StartTime and EndTime. See also Unit of time
Span.Attributes Add to Span.tags See Attributes for data types for the mapping.
Span.DroppedAttributesCount Add to Span.tags See Dropped Attributes Count for tag name to use.
Span.Events Span.annotations See Events for the mapping format.
Span.DroppedEventsCount Add to Span.tags See Dropped Events Count for tag name to use.
Span.Links TBD TBD
Span.DroppedLinksCount Add to Span.tags See Dropped Links Count for tag name to use.
Span.Status Add to Span.tags See Status for tag names to use.

TBD : This is work in progress document and it is currently doesn’t specify mapping for these fields:

OpenTelemetry fields:

  • Resource attributes
  • Tracestate
  • Links

Zipkin fields:

  • local_endpoint
  • debug
  • shared


This section discusses the details of the transformations between OpenTelemetry and Zipkin.

Service name

Zipkin service name MUST be set to the value of the resource attribute: If no is contained in a Span’s Resource, it MUST be populated from the default Resource. In Zipkin it is important that the service name is consistent for all spans in a local root. Otherwise service graph and aggregations would not work properly. OpenTelemetry doesn’t provide this consistency guarantee. Exporter may chose to override the value for service name based on a local root span to improve Zipkin user experience.

Note, the attribute service.namespace MUST NOT be used for the Zipkin service name and should be sent as a Zipkin tag.


The following table lists all the SpanKind mappings between OpenTelemetry and Zipkin.

OpenTelemetry Zipkin Note
SpanKind.INTERNAL null must be omitted (set to null)

Remote endpoint

OTLP -> Zipkin

If Zipkin SpanKind resolves to either SpanKind.CLIENT or SpanKind.PRODUCER then the service SHOULD specify remote endpoint otherwise Zipkin won’t treat the Span as a dependency. peer.service is the preferred attribute but is not always available. The following table lists the possible attributes for remoteEndpoint by preferred ranking:

Rank Attribute Name Reason
1 peer.service OpenTelemetry adopted attribute for remote service.
2 OpenTelemetry adopted attribute for remote hostname, or similar.
3 net.peer.ip & net.peer.port OpenTelemetry adopted attribute for remote address of the peer.
4 peer.hostname Remote hostname defined in OpenTracing specification.
5 peer.address Remote address defined in OpenTracing specification.
6 Commonly used HTTP host header attribute for Http Spans.
7 Commonly used database name attribute for DB Spans.
  • Ranking should control the selection order. For example, (Rank 2) should be selected before (Rank 6).
  • net.peer.ip can be used by itself as remoteEndpoint but should be combined with net.peer.port if it is also present.

Zipkin -> OTLP

When mapping from Zipkin to OTLP set peer.service tag from remoteEndpoint unless there is a peer.service tag defined explicitly.


OpenTelemetry Span Attribute(s) MUST be reported as tags to Zipkin.

Some attributes defined in semantic convention document maps to the strongly-typed fields of Zipkin spans.

Primitive types MUST be converted to string using en-US culture settings. Boolean values MUST use lower case strings "true" and "false".

Array values MUST be serialized to string like a JSON list as mentioned in semantic conventions.

TBD: add examples


This section overrides the generic Status mapping rule.

Span Status MUST be reported as a key-value pair in tags to Zipkin, unless it is UNSET. In the latter case it MUST NOT be reported.

The following table defines the OpenTelemetry Status to Zipkin tags mapping.

Status Tag Key Tag Value
Code otel.status_code Name of the code, either OK or ERROR. MUST NOT be set if the code is UNSET.
Description error Description of the Status. MUST be set if the code is ERROR, use an empty string if Description has no value. MUST NOT be set for OK and UNSET codes.

Note: The error tag should only be set if Status is Error. If a boolean version ({"error":false} or {"error":"false"}) is present, it SHOULD be removed. Zipkin will treat any span with error sent as failed.


OpenTelemetry Event has an optional Attribute(s) which is not supported by Zipkin. Events MUST be converted to the Annotations with the names which will include attribute values like this:

"my-event-name": { "key1" : "value1", "key2": "value2" }

Unit of Time

Zipkin times like timestamp, duration and annotation.timestamp MUST be reported in microseconds as whole numbers. For example, duration of 1234 nanoseconds will be represented as 1 microsecond.

Request Payload

For performance considerations, Zipkin fields that can be absent SHOULD be omitted from the payload when they are empty in the OpenTelemetry Span.

For example, an OpenTelemetry Span without any Event should not have an annotations field in the Zipkin payload.

Considerations for Legacy (v1) Format

Zipkin’s v2 json format was defined in 2017, followed up by a protobuf format in 2018.

Frameworks made before then use a more complex v1 Thrift or json format that notably differs in so far as it uses terminology such as Binary Annotation, and repeats endpoint information on each attribute.

Consider using as a reference implementation for converting v1 model to OpenTelemetry.

The span timestamp and duration were late additions to the V1 format. As in the code link above, it is possible to heuristically derive them from annotations.