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.

Span.KindSpan.kindSee SpanKind for values mapping
Span.StartTimeSpan.timestampSee Unit of time
Span.EndTimeSpan.durationDuration is calculated based on StartTime and EndTime. See also Unit of time
Span.AttributesAdd to Span.tagsSee Attributes for data types for the mapping.
Span.DroppedAttributesCountAdd to Span.tagsSee Dropped Attributes Count for tag name to use.
Span.EventsSpan.annotationsSee Events for the mapping format.
Span.DroppedEventsCountAdd to Span.tagsSee Dropped Events Count for tag name to use.
Span.DroppedLinksCountAdd to Span.tagsSee Dropped Links Count for tag name to use.
Span.StatusAdd to Span.tagsSee 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.

SpanKind.INTERNALnullmust 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:

RankAttribute NameReason
1peer.serviceOpenTelemetry adopted attribute for remote service.
2net.peer.nameOpenTelemetry adopted attribute for remote hostname, or similar.
3net.peer.ip & net.peer.portOpenTelemetry adopted attribute for remote address of the peer.
4peer.hostnameRemote hostname defined in OpenTracing specification.
5peer.addressRemote address defined in OpenTracing specification.
6http.hostCommonly used HTTP host header attribute for Http Spans.
7db.nameCommonly 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.

StatusTag KeyTag Value
Codeotel.status_codeName of the code, either OK or ERROR. MUST NOT be set if the code is UNSET.
DescriptionerrorDescription 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.