# Propagation

> Context propagation for the JS SDK

---

LLMS index: [llms.txt](/llms.txt)

---


With context propagation, [Signals](/docs/concepts/signals/) can be correlated
with each other, regardless of where they are generated. Although not limited to
tracing, context propagation allows [traces](/docs/concepts/signals/traces/) to
build causal information about a system across services that are arbitrarily
distributed across process and network boundaries.

For the vast majority of use cases, libraries that natively support
OpenTelemetry or [instrumentation libraries](../libraries/) will automatically
propagate trace context across services for you. It is only in rare cases that
you will need to propagate context manually.



To learn more, see [Context propagation](/docs/concepts/context-propagation).




{{__hugo_ctx/}}




> [!NOTE]
>
> The OpenTelemetry documentation assumes that the compiled application is run
> as [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules).
> If the application runs as ESM, add the loader hook as specified in the
> [ESM Support Doc](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md).
{{__hugo_ctx/}}


## Automatic context propagation

[Instrumentation libraries](../libraries/) like
[`@opentelemetry/instrumentation-http`](https://www.npmjs.com/package/@opentelemetry/instrumentation-http)
or
[`@opentelemetry/instrumentation-express`](https://www.npmjs.com/package/@opentelemetry/instrumentation-express)
propagate context across services for you.

If you followed the [Getting Started Guide](../getting-started/nodejs) you can
create a client application that queries the `/rolldice` endpoint.

> [!NOTE]
>
> You can combine this example with the sample application from the Getting
> Started guide of any other language as well. Correlation works across
> applications written in different languages without any differences.

Start by creating a new folder called `dice-client` and install the required
dependencies:

   <ul class="nav nav-tabs" id="tabs-2" role="tablist">
  <li class="nav-item">
      <button class="nav-link active"
          id="tabs-02-00-tab" data-bs-toggle="tab" data-bs-target="#tabs-02-00" role="tab"
          data-td-tp-persist="typescript" aria-controls="tabs-02-00" aria-selected="true">
        TypeScript
      </button>
    </li><li class="nav-item">
      <button class="nav-link"
          id="tabs-02-01-tab" data-bs-toggle="tab" data-bs-target="#tabs-02-01" role="tab"
          data-td-tp-persist="javascript" aria-controls="tabs-02-01" aria-selected="false">
        JavaScript
      </button>
    </li>
</ul>

<div class="tab-content" id="tabs-2-content">
    <div class="tab-body tab-pane fade show active"
        id="tabs-02-00" role="tabpanel" aria-labelled-by="tabs-02-00-tab" tabindex="2">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">npm init -y
</span></span><span class="line"><span class="cl">npm install undici <span class="se">\
</span></span></span><span class="line"><span class="cl">  @opentelemetry/instrumentation-undici <span class="se">\
</span></span></span><span class="line"><span class="cl">  @opentelemetry/sdk-node
</span></span><span class="line"><span class="cl">npm install -D tsx  <span class="c1"># a tool to run TypeScript (.ts) files directly with node</span>
</span></span></code></pre></div>
    </div>
    <div class="tab-body tab-pane fade"
        id="tabs-02-01" role="tabpanel" aria-labelled-by="tabs-02-01-tab" tabindex="2">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">npm init -y
</span></span><span class="line"><span class="cl">npm install undici <span class="se">\
</span></span></span><span class="line"><span class="cl">  @opentelemetry/instrumentation-undici <span class="se">\
</span></span></span><span class="line"><span class="cl">  @opentelemetry/sdk-node
</span></span></code></pre></div>
    </div>
</div>


Next, create a new file called `client.ts` (or `client.js`) with the following
content:

   <ul class="nav nav-tabs" id="tabs-3" role="tablist">
  <li class="nav-item">
      <button class="nav-link active"
          id="tabs-03-00-tab" data-bs-toggle="tab" data-bs-target="#tabs-03-00" role="tab"
          data-td-tp-persist="typescript" aria-controls="tabs-03-00" aria-selected="true">
        TypeScript
      </button>
    </li><li class="nav-item">
      <button class="nav-link"
          id="tabs-03-01-tab" data-bs-toggle="tab" data-bs-target="#tabs-03-01" role="tab"
          data-td-tp-persist="javascript" aria-controls="tabs-03-01" aria-selected="false">
        JavaScript
      </button>
    </li>
</ul>

<div class="tab-content" id="tabs-3-content">
    <div class="tab-body tab-pane fade show active"
        id="tabs-03-00" role="tabpanel" aria-labelled-by="tabs-03-00-tab" tabindex="3">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="cm">/* client.ts */</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">NodeSDK</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@opentelemetry/sdk-node&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">SimpleSpanProcessor</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ConsoleSpanExporter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@opentelemetry/sdk-trace-node&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">UndiciInstrumentation</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@opentelemetry/instrumentation-undici&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">sdk</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">NodeSDK</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">spanProcessors</span><span class="o">:</span> <span class="p">[</span><span class="k">new</span> <span class="nx">SimpleSpanProcessor</span><span class="p">(</span><span class="k">new</span> <span class="nx">ConsoleSpanExporter</span><span class="p">())],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">instrumentations</span><span class="o">:</span> <span class="p">[</span><span class="k">new</span> <span class="nx">UndiciInstrumentation</span><span class="p">()],</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">sdk</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">request</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;undici&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">request</span><span class="p">(</span><span class="s1">&#39;http://localhost:8080/rolldice&#39;</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">response</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">json</span><span class="p">().</span><span class="nx">then</span><span class="p">((</span><span class="nx">json</span>: <span class="kt">any</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">json</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div>
    </div>
    <div class="tab-body tab-pane fade"
        id="tabs-03-01" role="tabpanel" aria-labelled-by="tabs-03-01-tab" tabindex="3">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="cm">/* instrumentation.mjs */</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">NodeSDK</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@opentelemetry/sdk-node&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">SimpleSpanProcessor</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ConsoleSpanExporter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@opentelemetry/sdk-trace-node&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">UndiciInstrumentation</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@opentelemetry/instrumentation-undici&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">sdk</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">NodeSDK</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">spanProcessors</span><span class="o">:</span> <span class="p">[</span><span class="k">new</span> <span class="nx">SimpleSpanProcessor</span><span class="p">(</span><span class="k">new</span> <span class="nx">ConsoleSpanExporter</span><span class="p">())],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">instrumentations</span><span class="o">:</span> <span class="p">[</span><span class="k">new</span> <span class="nx">UndiciInstrumentation</span><span class="p">()],</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">sdk</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">request</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;undici&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">request</span><span class="p">(</span><span class="s1">&#39;http://localhost:8080/rolldice&#39;</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">response</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">response</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">json</span><span class="p">().</span><span class="nx">then</span><span class="p">((</span><span class="nx">json</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">json</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div>
    </div>
</div>


Make sure that you have the instrumented version of `app.ts` (or `app.js`) from
the [Getting Started](../getting-started/nodejs) running in one shell:

   <ul class="nav nav-tabs" id="tabs-4" role="tablist">
  <li class="nav-item">
      <button class="nav-link active"
          id="tabs-04-00-tab" data-bs-toggle="tab" data-bs-target="#tabs-04-00" role="tab"
          data-td-tp-persist="typescript" aria-controls="tabs-04-00" aria-selected="true">
        TypeScript
      </button>
    </li><li class="nav-item">
      <button class="nav-link"
          id="tabs-04-01-tab" data-bs-toggle="tab" data-bs-target="#tabs-04-01" role="tab"
          data-td-tp-persist="javascript" aria-controls="tabs-04-01" aria-selected="false">
        JavaScript
      </button>
    </li>
</ul>

<div class="tab-content" id="tabs-4-content">
    <div class="tab-body tab-pane fade show active"
        id="tabs-04-00" role="tabpanel" aria-labelled-by="tabs-04-00-tab" tabindex="4">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> npx tsx --import ./instrumentation.ts app.ts
</span></span><span class="line"><span class="cl"><span class="go">Listening for requests on http://localhost:8080
</span></span></span></code></pre></div>
    </div>
    <div class="tab-body tab-pane fade"
        id="tabs-04-01" role="tabpanel" aria-labelled-by="tabs-04-01-tab" tabindex="4">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> node --import ./instrumentation.mjs app.js
</span></span><span class="line"><span class="cl"><span class="go">Listening for requests on http://localhost:8080
</span></span></span></code></pre></div>
    </div>
</div>


Start a second shell and run the `client.ts` (or `client.js`):

   <ul class="nav nav-tabs" id="tabs-5" role="tablist">
  <li class="nav-item">
      <button class="nav-link active"
          id="tabs-05-00-tab" data-bs-toggle="tab" data-bs-target="#tabs-05-00" role="tab"
          data-td-tp-persist="typescript" aria-controls="tabs-05-00" aria-selected="true">
        TypeScript
      </button>
    </li><li class="nav-item">
      <button class="nav-link"
          id="tabs-05-01-tab" data-bs-toggle="tab" data-bs-target="#tabs-05-01" role="tab"
          data-td-tp-persist="javascript" aria-controls="tabs-05-01" aria-selected="false">
        JavaScript
      </button>
    </li>
</ul>

<div class="tab-content" id="tabs-5-content">
    <div class="tab-body tab-pane fade show active"
        id="tabs-05-00" role="tabpanel" aria-labelled-by="tabs-05-00-tab" tabindex="5">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">npx tsx client.ts
</span></span></code></pre></div>
    </div>
    <div class="tab-body tab-pane fade"
        id="tabs-05-01" role="tabpanel" aria-labelled-by="tabs-05-01-tab" tabindex="5">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">node client.js
</span></span></code></pre></div>
    </div>
</div>


Both shells should emit span details to the console. The client output looks
similar to the following:

```javascript {hl_lines=[7,11]}
{
  resource: {
    attributes: {
      // ...
    }
  },
  traceId: 'cccd19c3a2d10e589f01bfe2dc896dc2',
  parentSpanContext: undefined,
  traceState: undefined,
  name: 'GET',
  id: '6f64ce484217a7bf',
  kind: 2,
  timestamp: 1718875320295000,
  duration: 19836.833,
  attributes: {
    'url.full': 'http://localhost:8080/rolldice',
    // ...
  },
  status: { code: 0 },
  events: [],
  links: []
}
```

Take note of the traceId (`cccd19c3a2d10e589f01bfe2dc896dc2`) and ID
(`6f64ce484217a7bf`). Both can be found in the output of client as well:

```javascript {hl_lines=[6,9]}
{
  resource: {
    attributes: {
      // ...
    }
  },
  traceId: 'cccd19c3a2d10e589f01bfe2dc896dc2',
  parentSpanContext: {
    traceId: 'cccd19c3a2d10e589f01bfe2dc896dc2',
    spanId: '6f64ce484217a7bf',
    traceFlags: 1,
    isRemote: true
  },
  traceState: undefined,
  name: 'GET /rolldice',
  id: '027c5c8b916d29da',
  kind: 1,
  timestamp: 1718875320310000,
  duration: 3894.792,
  attributes: {
    'http.url': 'http://localhost:8080/rolldice',
    // ...
  },
  status: { code: 0 },
  events: [],
  links: []
}
```

Your client and server application successfully report connected spans. If you
send both to a backend now the visualization will show this dependency for you.

## Manual context propagation

In some cases, it is not possible to propagate context automatically as outlined
in the previous section. There might not be an instrumentation library that
matches a library you're using to have services communicate with one another. Or
you might have requirements that these libraries can't fulfill even if they
existed.

When you must propagate context manually, you can use the
[context API](/docs/languages/js/context).

### Generic example

The following generic example demonstrates how you can propagate trace context
manually.

First, on the sending service, you'll need to inject the current `context`:

   <ul class="nav nav-tabs" id="tabs-6" role="tablist">
  <li class="nav-item">
      <button class="nav-link active"
          id="tabs-06-00-tab" data-bs-toggle="tab" data-bs-target="#tabs-06-00" role="tab"
          data-td-tp-persist="typescript" aria-controls="tabs-06-00" aria-selected="true">
        TypeScript
      </button>
    </li><li class="nav-item">
      <button class="nav-link"
          id="tabs-06-01-tab" data-bs-toggle="tab" data-bs-target="#tabs-06-01" role="tab"
          data-td-tp-persist="javascript" aria-controls="tabs-06-01" aria-selected="false">
        JavaScript
      </button>
    </li>
</ul>

<div class="tab-content" id="tabs-6-content">
    <div class="tab-body tab-pane fade show active"
        id="tabs-06-00" role="tabpanel" aria-labelled-by="tabs-06-00-tab" tabindex="6">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// Sending service
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">context</span><span class="p">,</span> <span class="nx">propagation</span><span class="p">,</span> <span class="nx">trace</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@opentelemetry/api&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Define an interface for the output object that will hold the trace information.
</span></span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Carrier</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">traceparent?</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">tracestate?</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Create an output object that conforms to that interface.
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">output</span>: <span class="kt">Carrier</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Serialize the traceparent and tracestate from context into
</span></span></span><span class="line"><span class="cl"><span class="c1">// an output object.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// This example uses the active trace context, but you can
</span></span></span><span class="line"><span class="cl"><span class="c1">// use whatever context is appropriate to your scenario.
</span></span></span><span class="line"><span class="cl"><span class="nx">propagation</span><span class="p">.</span><span class="nx">inject</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nx">active</span><span class="p">(),</span> <span class="nx">output</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Extract the traceparent and tracestate values from the output object.
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">traceparent</span><span class="p">,</span> <span class="nx">tracestate</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">output</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// You can then pass the traceparent and tracestate
</span></span></span><span class="line"><span class="cl"><span class="c1">// data to whatever mechanism you use to propagate
</span></span></span><span class="line"><span class="cl"><span class="c1">// across services.
</span></span></span></code></pre></div>
    </div>
    <div class="tab-body tab-pane fade"
        id="tabs-06-01" role="tabpanel" aria-labelled-by="tabs-06-01-tab" tabindex="6">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// Sending service
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">context</span><span class="p">,</span> <span class="nx">propagation</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;@opentelemetry/api&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">output</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Serialize the traceparent and tracestate from context into
</span></span></span><span class="line"><span class="cl"><span class="c1">// an output object.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// This example uses the active trace context, but you can
</span></span></span><span class="line"><span class="cl"><span class="c1">// use whatever context is appropriate to your scenario.
</span></span></span><span class="line"><span class="cl"><span class="nx">propagation</span><span class="p">.</span><span class="nx">inject</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nx">active</span><span class="p">(),</span> <span class="nx">output</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">traceparent</span><span class="p">,</span> <span class="nx">tracestate</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">output</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// You can then pass the traceparent and tracestate
</span></span></span><span class="line"><span class="cl"><span class="c1">// data to whatever mechanism you use to propagate
</span></span></span><span class="line"><span class="cl"><span class="c1">// across services.
</span></span></span></code></pre></div>
    </div>
</div>


On the receiving service, you'll need to extract `context` (for example, from
parsed HTTP headers) and then set them as the current trace context.

   <ul class="nav nav-tabs" id="tabs-7" role="tablist">
  <li class="nav-item">
      <button class="nav-link active"
          id="tabs-07-00-tab" data-bs-toggle="tab" data-bs-target="#tabs-07-00" role="tab"
          data-td-tp-persist="typescript" aria-controls="tabs-07-00" aria-selected="true">
        TypeScript
      </button>
    </li><li class="nav-item">
      <button class="nav-link"
          id="tabs-07-01-tab" data-bs-toggle="tab" data-bs-target="#tabs-07-01" role="tab"
          data-td-tp-persist="javascript" aria-controls="tabs-07-01" aria-selected="false">
        JavaScript
      </button>
    </li>
</ul>

<div class="tab-content" id="tabs-7-content">
    <div class="tab-body tab-pane fade show active"
        id="tabs-07-00" role="tabpanel" aria-labelled-by="tabs-07-00-tab" tabindex="7">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// Receiving service
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">type</span> <span class="nx">Context</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">propagation</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">trace</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Span</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">context</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@opentelemetry/api&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Define an interface for the input object that includes &#39;traceparent&#39; &amp; &#39;tracestate&#39;.
</span></span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Carrier</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">traceparent?</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">tracestate?</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Assume &#34;input&#34; is an object with &#39;traceparent&#39; &amp; &#39;tracestate&#39; keys.
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">input</span>: <span class="kt">Carrier</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Extracts the &#39;traceparent&#39; and &#39;tracestate&#39; data into a context object.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// You can then treat this context as the active context for your
</span></span></span><span class="line"><span class="cl"><span class="c1">// traces.
</span></span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">activeContext</span>: <span class="kt">Context</span> <span class="o">=</span> <span class="nx">propagation</span><span class="p">.</span><span class="nx">extract</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nx">active</span><span class="p">(),</span> <span class="nx">input</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">tracer</span> <span class="o">=</span> <span class="nx">trace</span><span class="p">.</span><span class="nx">getTracer</span><span class="p">(</span><span class="s1">&#39;app-name&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">span</span>: <span class="kt">Span</span> <span class="o">=</span> <span class="nx">tracer</span><span class="p">.</span><span class="nx">startSpan</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">spanName</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">attributes</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">activeContext</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Set the created span as active in the deserialized context.
</span></span></span><span class="line"><span class="cl"><span class="nx">trace</span><span class="p">.</span><span class="nx">setSpan</span><span class="p">(</span><span class="nx">activeContext</span><span class="p">,</span> <span class="nx">span</span><span class="p">);</span>
</span></span></code></pre></div>
    </div>
    <div class="tab-body tab-pane fade"
        id="tabs-07-01" role="tabpanel" aria-labelled-by="tabs-07-01-tab" tabindex="7">
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// Receiving service
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">context</span><span class="p">,</span> <span class="nx">propagation</span><span class="p">,</span> <span class="nx">trace</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@opentelemetry/api&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Assume &#34;input&#34; is an object with &#39;traceparent&#39; &amp; &#39;tracestate&#39; keys
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">input</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Extracts the &#39;traceparent&#39; and &#39;tracestate&#39; data into a context object.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// You can then treat this context as the active context for your
</span></span></span><span class="line"><span class="cl"><span class="c1">// traces.
</span></span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">activeContext</span> <span class="o">=</span> <span class="nx">propagation</span><span class="p">.</span><span class="nx">extract</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nx">active</span><span class="p">(),</span> <span class="nx">input</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">tracer</span> <span class="o">=</span> <span class="nx">trace</span><span class="p">.</span><span class="nx">getTracer</span><span class="p">(</span><span class="s1">&#39;app-name&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">span</span> <span class="o">=</span> <span class="nx">tracer</span><span class="p">.</span><span class="nx">startSpan</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">spanName</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">attributes</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">activeContext</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Set the created span as active in the deserialized context.
</span></span></span><span class="line"><span class="cl"><span class="nx">trace</span><span class="p">.</span><span class="nx">setSpan</span><span class="p">(</span><span class="nx">activeContext</span><span class="p">,</span> <span class="nx">span</span><span class="p">);</span>
</span></span></code></pre></div>
    </div>
</div>


From there, when you have a deserialized active context, you can create spans
that will be a part of the same trace from the other service.

You can also use the [Context](/docs/languages/js/context) API to modify or set
the deserialized context in other ways.

### Custom protocol example

A common use case for when you need to propagate context manually is when you
use a custom protocol between services for communication. The following example
uses a basic text-based TCP protocol to send a serialized object from one
service to another.

Start with creating a new folder called `propagation-example` and initialize it
with dependencies as follows:

```shell
npm init -y
npm install @opentelemetry/api @opentelemetry/sdk-node
```

Next create files `client.js` and `server.js` with the following content:

```javascript
// client.js
const net = require('net');
const { context, propagation, trace } = require('@opentelemetry/api');

let tracer = trace.getTracer('client');

// Connect to the server
const client = net.createConnection({ port: 8124 }, () => {
  // Send the serialized object to the server
  let span = tracer.startActiveSpan('send', { kind: 1 }, (span) => {
    const output = {};
    propagation.inject(context.active(), output);
    const { traceparent, tracestate } = output;

    const objToSend = { key: 'value' };

    if (traceparent) {
      objToSend._meta = { traceparent, tracestate };
    }

    client.write(JSON.stringify(objToSend), () => {
      client.end();
      span.end();
    });
  });
});
```

```javascript
// server.js
const net = require('net');
const { context, propagation, trace } = require('@opentelemetry/api');

let tracer = trace.getTracer('server');

const server = net.createServer((socket) => {
  socket.on('data', (data) => {
    const message = data.toString();
    // Parse the JSON object received from the client
    try {
      const json = JSON.parse(message);
      let activeContext = context.active();
      if (json._meta) {
        activeContext = propagation.extract(context.active(), json._meta);
        delete json._meta;
      }
      span = tracer.startSpan('receive', { kind: 1 }, activeContext);
      trace.setSpan(activeContext, span);
      console.log('Parsed JSON:', json);
    } catch (e) {
      console.error('Error parsing JSON:', e.message);
    } finally {
      span.end();
    }
  });
});

// Listen on port 8124
server.listen(8124, () => {
  console.log('Server listening on port 8124');
});
```

Start a first shell to run the server:

```console
$ node server.js
Server listening on port 8124
```

Then in a second shell run the client:

```shell
node client.js
```

The client should terminate immediately and the server should output the
following:

```text
Parsed JSON: { key: 'value' }
```

Since the example so far only took dependency on the OpenTelemetry API all calls
to it are [no-op instructions](<https://en.wikipedia.org/wiki/NOP_(code)>) and
the client and server behave as if OpenTelemetry is not used.

> [!IMPORTANT]
>
> This is especially important if your server and client code are libraries,
> since they should only use the OpenTelemetry API. To understand why, read the
> [concept page on how to add instrumentation to your library](/docs/concepts/instrumentation/libraries/).

To enable OpenTelemetry and see the context propagation in action, create an
additional file called `instrumentation.js` with the following content:

```javascript
// instrumentation.mjs
import { NodeSDK } from '@opentelemetry/sdk-node';
import {
  ConsoleSpanExporter,
  SimpleSpanProcessor,
} from '@opentelemetry/sdk-trace-node';

const sdk = new NodeSDK({
  spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())],
});

sdk.start();
```

Use this file to run both, the server and the client, with instrumentation
enabled:

```console
$ node --import ./instrumentation.mjs server.js
Server listening on port 8124
```

and

```shell
node --import ./instrumentation.mjs client.js
```

After the client has sent data to the server and terminated you should see spans
in the console output of both shells.

The output for the client looks like the following:

```javascript {hl_lines=[7,11]}
{
  resource: {
    attributes: {
      // ...
    }
  },
  traceId: '4b5367d540726a70afdbaf49240e6597',
  parentId: undefined,
  traceState: undefined,
  name: 'send',
  id: '92f125fa335505ec',
  kind: 1,
  timestamp: 1718879823424000,
  duration: 1054.583,
  // ...
}
```

The output for the server looks like the following:

```javascript {hl_lines=[7,8]}
{
  resource: {
    attributes: {
      // ...
    }
  },
  traceId: '4b5367d540726a70afdbaf49240e6597',
  parentId: '92f125fa335505ec',
  traceState: undefined,
  name: 'receive',
  id: '53da0c5f03cb36e5',
  kind: 1,
  timestamp: 1718879823426000,
  duration: 959.541,
  // ...
}
```

Similar to the [manual example](#manual-context-propagation) the spans are
connected using the `traceId` and the `id`/`parentId`.

## Next steps

To learn more about propagation, read the
[Propagators API specification](/docs/specs/otel/context/api-propagators/).
