> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/getsentry/sentry-javascript/llms.txt
> Use this file to discover all available pages before exploring further.

# Propagation

> Propagate traces across services and boundaries

Trace propagation enables distributed tracing by passing trace context between services, processes, and systems.

## Overview

Propagation involves:

* Extracting trace context from incoming requests
* Injecting trace context into outgoing requests
* Maintaining parent-child relationships across services
* Preserving sampling decisions

## Trace Headers

### sentry-trace

The primary header for Sentry tracing:

**Format:** `{trace_id}-{span_id}-{sampled}`

```
sentry-trace: 1234567890abcdef1234567890abcdef-1234567890abcdef-1
```

* `trace_id`: 32 hex characters (128 bits)
* `span_id`: 16 hex characters (64 bits)
* `sampled`: `1` (sampled) or `0` (not sampled)

### baggage

Contains dynamic sampling context:

**Format:** Key-value pairs separated by commas

```
baggage: sentry-trace_id=1234...,sentry-public_key=abc...,sentry-release=1.0.0
```

### traceparent (W3C)

Optional W3C Trace Context standard:

**Format:** `{version}-{trace_id}-{parent_id}-{flags}`

```
traceparent: 00-1234567890abcdef1234567890abcdef-1234567890abcdef-01
```

## Automatic Propagation

Sentry automatically propagates traces for HTTP requests:

```typescript theme={null}
import * as Sentry from '@sentry/node';
import { httpIntegration } from '@sentry/node';

Sentry.init({
  dsn: 'your-dsn',
  integrations: [
    httpIntegration({
      tracing: true // Enables automatic propagation
    })
  ],
  // Control which requests get tracing headers
  tracePropagationTargets: [
    'localhost',
    /^https:\/\/api\.myapp\.com/
  ]
});

// Headers automatically added to outgoing requests
await fetch('https://api.myapp.com/users');
// Includes: sentry-trace, baggage headers
```

## tracePropagationTargets

Control which outgoing requests receive tracing headers:

```typescript theme={null}
import * as Sentry from '@sentry/node';

Sentry.init({
  dsn: 'your-dsn',
  tracePropagationTargets: [
    // String matching (partial match)
    'api.myapp.com',
    'internal-service',
    
    // RegExp matching
    /^https:\/\/api\./,
    /\.myapp\.com$/,
    
    // Relative URLs (browser only)
    /^\/api\//
  ]
});
```

**Default Behavior:**

* **Node.js:** All outgoing requests
* **Browser:** Same-origin requests only

## Manual Propagation

### Outgoing Requests

```typescript theme={null}
import * as Sentry from '@sentry/node';
import { spanToTraceHeader, spanToBaggageHeader } from '@sentry/core';

const span = Sentry.getActiveSpan();

if (span) {
  const headers = {
    'sentry-trace': spanToTraceHeader(span),
    'baggage': spanToBaggageHeader(span)
  };
  
  await fetch('https://api.example.com/data', { headers });
}
```

### Incoming Requests

```typescript theme={null}
import * as Sentry from '@sentry/node';
import type { Request, Response, NextFunction } from 'express';

app.use((req: Request, res: Response, next: NextFunction) => {
  Sentry.continueTrace(
    {
      sentryTrace: req.headers['sentry-trace'] as string,
      baggage: req.headers['baggage'] as string
    },
    () => {
      // Request handling continues the trace
      next();
    }
  );
});
```

## continueTrace

Continue a trace from incoming headers:

```typescript theme={null}
export function continueTrace<V>(
  {
    sentryTrace,
    baggage,
  }: {
    sentryTrace?: string;
    baggage?: string | string[];
  },
  callback: () => V,
): V
```

<ParamField path="sentryTrace" type="string">
  The `sentry-trace` header value.
</ParamField>

<ParamField path="baggage" type="string | string[]">
  The `baggage` header value(s).
</ParamField>

<ParamField path="callback" type="function" required>
  Function to execute with the continued trace.
</ParamField>

**Example:**

```typescript theme={null}
import * as Sentry from '@sentry/node';

const result = Sentry.continueTrace(
  {
    sentryTrace: request.headers['sentry-trace'],
    baggage: request.headers['baggage']
  },
  () => {
    // Process request with continued trace
    return Sentry.startSpan(
      { name: 'Process Request', op: 'http.server' },
      () => processRequest()
    );
  }
);
```

## Cross-Service Tracing

### Service A (Origin)

```typescript theme={null}
import * as Sentry from '@sentry/node';
import { spanToTraceHeader, spanToBaggageHeader } from '@sentry/core';

await Sentry.startSpan(
  { name: 'Call Service B', op: 'http.client' },
  async (span) => {
    const response = await fetch('https://service-b.example.com/api', {
      headers: {
        'sentry-trace': spanToTraceHeader(span),
        'baggage': spanToBaggageHeader(span)
      }
    });
    return response.json();
  }
);
```

### Service B (Receiver)

```typescript theme={null}
import * as Sentry from '@sentry/node';

app.post('/api', (req, res) => {
  Sentry.continueTrace(
    {
      sentryTrace: req.headers['sentry-trace'],
      baggage: req.headers['baggage']
    },
    () => {
      Sentry.startSpan(
        { name: 'Handle Request', op: 'http.server' },
        async () => {
          const result = await handleRequest(req);
          res.json(result);
        }
      );
    }
  );
});
```

## W3C Trace Context

Enable W3C `traceparent` header:

```typescript theme={null}
import * as Sentry from '@sentry/node';

Sentry.init({
  dsn: 'your-dsn',
  propagateTraceparent: true,
  tracePropagationTargets: ['example.com']
});

// Outgoing requests now include:
// - sentry-trace
// - baggage  
// - traceparent (W3C)
```

**CORS Considerations:**

When enabling `traceparent`, ensure your server allows it:

```javascript theme={null}
// Server CORS config
res.setHeader(
  'Access-Control-Allow-Headers',
  'sentry-trace, baggage, traceparent'
);
```

## Browser Propagation

### Server-Side Rendering

Pass trace context from server to browser:

```typescript theme={null}
// Server (e.g., Next.js, Remix)
import * as Sentry from '@sentry/node';
import { spanToTraceHeader, getDynamicSamplingContextFromSpan } from '@sentry/core';

const span = Sentry.getActiveSpan();

if (span) {
  const sentryTrace = spanToTraceHeader(span);
  const dsc = getDynamicSamplingContextFromSpan(span);
  const baggage = dynamicSamplingContextToSentryBaggageHeader(dsc);
  
  // Inject into HTML
  const html = `
    <html>
      <head>
        <meta name="sentry-trace" content="${sentryTrace}" />
        <meta name="baggage" content="${baggage}" />
      </head>
      <body>...</body>
    </html>
  `;
}
```

### Client-Side

```typescript theme={null}
// Browser
import * as Sentry from '@sentry/browser';

Sentry.init({
  dsn: 'your-dsn'
});

// Continue trace from meta tags
const sentryTrace = document
  .querySelector('meta[name="sentry-trace"]')
  ?.getAttribute('content');

const baggage = document
  .querySelector('meta[name="baggage"]')
  ?.getAttribute('content');

if (sentryTrace) {
  Sentry.continueTrace({ sentryTrace, baggage }, () => {
    // Browser continues server trace
  });
}
```

## Message Queues

Propagate traces through async message queues:

### Producer

```typescript theme={null}
import * as Sentry from '@sentry/node';
import { spanToTraceHeader, spanToBaggageHeader } from '@sentry/core';

const span = Sentry.getActiveSpan();

if (span) {
  const message = {
    data: payload,
    _sentry: {
      trace: spanToTraceHeader(span),
      baggage: spanToBaggageHeader(span)
    }
  };
  
  await queue.publish(message);
}
```

### Consumer

```typescript theme={null}
import * as Sentry from '@sentry/node';

queue.subscribe(async (message) => {
  Sentry.continueTrace(
    {
      sentryTrace: message._sentry.trace,
      baggage: message._sentry.baggage
    },
    () => {
      Sentry.startSpan(
        { name: 'Process Message', op: 'queue.process' },
        () => processMessage(message)
      );
    }
  );
});
```

## Database Connections

Propagate context through database operations:

```typescript theme={null}
import * as Sentry from '@sentry/node';
import { spanToTraceHeader } from '@sentry/core';

const span = Sentry.getActiveSpan();

if (span) {
  // Add trace context as SQL comment
  const traceComment = `/* sentry:${spanToTraceHeader(span)} */`;
  const query = `${traceComment} SELECT * FROM users`;
  
  await db.query(query);
}
```

## Organization-Based Trace Continuation

Limit trace continuation to same organization:

```typescript theme={null}
import * as Sentry from '@sentry/node';

Sentry.init({
  dsn: 'your-dsn',
  
  // Only continue traces from same org
  traceContinuationOnlyIfSameOrg: true,
  
  // Optional: explicitly set org ID
  orgId: 'your-org-id'
});

// Traces from other orgs start new trace
```

## Custom Propagation

Implement custom propagation logic:

```typescript theme={null}
import * as Sentry from '@sentry/node';
import type { Span } from '@sentry/types';

function propagateTraceToCustomProtocol(span: Span): Record<string, string> {
  const context = span.spanContext();
  
  return {
    'X-Trace-ID': context.traceId,
    'X-Span-ID': context.spanId,
    'X-Sampled': context.traceFlags === 1 ? 'true' : 'false'
  };
}

// Use with custom protocol
const span = Sentry.getActiveSpan();
if (span) {
  const headers = propagateTraceToCustomProtocol(span);
  await customProtocol.send({ headers, data });
}
```

## Best Practices

### 1. Always Propagate Sampled Traces

```typescript theme={null}
const span = Sentry.getActiveSpan();
if (span && span.isRecording()) {
  // Only add headers if span is sampled
  headers['sentry-trace'] = spanToTraceHeader(span);
}
```

### 2. Handle Missing Headers Gracefully

```typescript theme={null}
app.use((req, res, next) => {
  const sentryTrace = req.headers['sentry-trace'];
  
  if (sentryTrace) {
    Sentry.continueTrace({ sentryTrace }, () => next());
  } else {
    // Start new trace
    next();
  }
});
```

### 3. Be Careful with CORS

```typescript theme={null}
// Only propagate to controlled origins
Sentry.init({
  tracePropagationTargets: [
    /^https:\/\/api\.myapp\.com/,
    // Don't add third-party APIs
  ]
});
```

### 4. Validate Incoming Headers

```typescript theme={null}
function isValidSentryTrace(trace: string): boolean {
  // Format: traceId-spanId-sampled
  const pattern = /^[a-f0-9]{32}-[a-f0-9]{16}-[01]$/;
  return pattern.test(trace);
}

if (sentryTrace && isValidSentryTrace(sentryTrace)) {
  Sentry.continueTrace({ sentryTrace }, callback);
}
```

## Related

* [Spans](/api/tracing/spans)
* [Trace Context](/api/tracing/trace-context)
* [Configuration](/api/configuration/options)
* [HTTP Integration](/api/core/integrations)
