All Products
Search
Document Center

Application Real-Time Monitoring Service:Return trace IDs in HTTP response headers

Last Updated:Mar 11, 2026

By default, the OpenTelemetry agent includes trace IDs only in HTTP request headers. Returning trace IDs in HTTP response headers lets API consumers and frontend systems correlate specific HTTP responses with their backend distributed traces -- making it straightforward to debug user-reported issues and trace requests end to end.

This topic covers Java and Node.js implementations:

LanguageApproachEffortWhen to use
JavaPre-built extension JARLowDefault choice. Works out of the box with no custom code.
JavaCustom agent extensionMediumThe pre-built extension does not meet your requirements.
Node.jsresponseHook in HttpInstrumentationLowStandard approach for Node.js applications.

Java

Both methods below use the OpenTelemetry Java agent extension mechanism to inject TraceId and SpanId headers into HTTP responses.

Method 1: Use the pre-built extension

Managed Service for OpenTelemetry provides a pre-built extension JAR that adds TraceId and SpanId headers to every HTTP response automatically. No custom code is required.

  1. Download the extension JAR: ot-java-agent-extension-1.28.0.jar.

  2. Add -Dotel.javaagent.extensions to the startup command, pointing to the downloaded JAR: Replace the following placeholders with actual values:

    PlaceholderDescription
    <token>Authentication token for the OTLP exporter
    <endpoint>OTLP endpoint URL of your Managed Service for OpenTelemetry instance
       java -javaagent:path/to/opentelemetry-javaagent.jar \
        -Dotel.javaagent.extensions=path/to/opentelemetry-java-agent-extension.jar \
        -Dotel.exporter.otlp.headers=Authentication=<token> \
        -Dotel.exporter.otlp.endpoint=<endpoint> \
        -Dotel.metrics.exporter=none \
        -jar your-app.jar

Method 2: Build a custom extension

If the pre-built extension does not meet your requirements, build a custom OpenTelemetry Java agent extension and package it as a JAR file.

Prerequisites

Before you begin, make sure that you have:

  • The OpenTelemetry Java agent configured

  • The OpenTelemetry Java agent version 1.24.0 or later

Procedure

  1. Create a project and add dependencies. Add the following to the pom.xml file:

    Important

    The opentelemetry-javaagent dependency version must match the version of the OpenTelemetry Java agent that your application uses.

       <dependencies>
        <dependency>
         <groupId>com.google.auto.service</groupId>
         <artifactId>auto-service</artifactId>
         <version>1.1.1</version>
        </dependency>
    
        <dependency>
         <groupId>io.opentelemetry.javaagent</groupId>
         <artifactId>opentelemetry-javaagent</artifactId>
         <version>1.28.0</version>
         <scope>compile</scope>
        </dependency>
       </dependencies>
  2. Create the AgentHttpResponseCustomizer class. This class implements HttpServerResponseCustomizer to inject the trace ID and span ID into HTTP responses:

       package org.example;
    
       import com.google.auto.service.AutoService;
       import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span;
       import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.SpanContext;
       import io.opentelemetry.javaagent.shaded.io.opentelemetry.context.Context;
       import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseCustomizer;
       import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseMutator;
    
       @AutoService(HttpServerResponseCustomizer.class)
       public class AgentHttpResponseCustomizer implements HttpServerResponseCustomizer {
        @Override
        public <RESPONSE> void customize(
            Context context,
            RESPONSE response,
            HttpServerResponseMutator<RESPONSE> responseMutator) {
    
         SpanContext spanContext = Span.fromContext(context).getSpanContext();
         String traceId = spanContext.getTraceId();
         String spanId = spanContext.getSpanId();
    
         // Add trace ID and span ID to the HTTP response header.
         // Change the header names to match your requirements.
         responseMutator.appendHeader(response, "TraceId", traceId);
         responseMutator.appendHeader(response, "SpanId", spanId);
        }
       }
  3. Build the extension JAR. The JAR file is generated in the target directory.

       mvn clean package
  4. Start the application with the extension. Add -Dotel.javaagent.extensions to the startup command, pointing to the built JAR:

       java -javaagent:path/to/opentelemetry-javaagent.jar \
        -Dotel.javaagent.extensions=path/to/opentelemetry-java-agent-extension.jar \
        -Dotel.exporter.otlp.headers=Authentication=<token> \
        -Dotel.exporter.otlp.endpoint=<endpoint> \
        -Dotel.metrics.exporter=none \
        -jar yourapp.jar

Node.js

For Node.js applications, add a responseHook to HttpInstrumentation to inject trace IDs into HTTP response headers.

Procedure

  1. (Optional) If the Node.js application is not yet integrated with OpenTelemetry, download the Node.js demo project and follow it to set up the integration first.

  2. Modify the HttpInstrumentation initialization to include a responseHook. This hook adds the trace ID and span ID to every HTTP response:

       // Replace the default HttpInstrumentation initialization:
       //
       // registerInstrumentations({
       //   tracerProvider: provider,
       //   instrumentations: [new HttpInstrumentation(), ExpressInstrumentation],
       // });
    
       // Create HttpInstrumentation with a custom responseHook:
       const httpInstrumentation = new HttpInstrumentation({
        responseHook: (span, response) => {
         // Get the trace ID and span ID from the span context
         const traceId = span.spanContext().traceId;
         const spanId = span.spanContext().spanId;
    
         // Add trace ID and span ID to the HTTP response header
         response.setHeader('TraceId', traceId);
         response.setHeader('SpanId', spanId);
    
         return response;
        },
       });
    
       registerInstrumentations({
        tracerProvider: provider,
        instrumentations: [httpInstrumentation, ExpressInstrumentation],
       });