> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getnetra.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Exporters

> Send Netra traces to your own OTLP-compatible backend or self-hosted stack. Configure custom exporters for Jaeger, Grafana Tempo, or any collector.

Netra uses the OpenTelemetry Protocol (OTLP) to export traces, making it compatible with any OTLP-compliant backend. This guide covers how to configure custom endpoints, authentication, and self-hosted setups.

## OTLP Endpoint Configuration

### Netra Cloud

By default, traces are sent to Netra's cloud backend. Configure the endpoint and API key:

<CodeGroup>
  ```python Python theme={null}
  import os
  from netra import Netra

  Netra.init(
      app_name="my-ai-app",
      headers=f"x-api-key={os.getenv('NETRA_API_KEY')}",
  )
  ```

  ```typescript TypeScript theme={null}
  import { Netra } from "netra-sdk";

  await Netra.init({
    appName: "my-ai-app",
    headers: `x-api-key=${process.env.NETRA_API_KEY}`,
  });
  ```
</CodeGroup>

Or via environment variables:

<CodeGroup>
  ```bash US Region theme={null}
  export NETRA_API_KEY="your-api-key"
  export NETRA_OTLP_ENDPOINT="https://api.getnetra.ai/telemetry"
  ```

  ```bash EU Region theme={null}
  export NETRA_API_KEY="your-api-key"
  export NETRA_OTLP_ENDPOINT="https://api.eu.getnetra.ai/telemetry"
  ```
</CodeGroup>

### Regional Endpoints

Netra provides regional endpoints for data residency requirements:

| Region | Location                 | Endpoint                               |
| ------ | ------------------------ | -------------------------------------- |
| **US** | N. Virginia (us-east-1)  | `https://api.getnetra.ai/telemetry`    |
| **EU** | Frankfurt (eu-central-1) | `https://api.eu.getnetra.ai/telemetry` |

<Note>
  Regions are strictly separated, and no data is shared across regions. Choosing a region close to you can help improve speed and comply with local data residency laws and privacy regulations.
</Note>

```bash theme={null}
# US region
export NETRA_OTLP_ENDPOINT="https://api.getnetra.ai/telemetry"

# EU region
export NETRA_OTLP_ENDPOINT="https://api.eu.getnetra.ai/telemetry"
```

## Custom Backend Configuration

### Setting a Custom Endpoint

Point Netra to any OTLP-compatible backend:

<CodeGroup>
  ```python Python theme={null}
  import os
  from netra import Netra

  # Set custom endpoint via environment variable
  os.environ["NETRA_OTLP_ENDPOINT"] = "https://otel-collector.internal.company.com"

  Netra.init(
      app_name="my-ai-app",
      headers="Authorization=Bearer your-token",
  )
  ```

  ```typescript TypeScript theme={null}
  import { Netra } from "netra-sdk";

  await Netra.init({
    appName: "my-ai-app",
    // Custom endpoint will have /v1/traces appended automatically
    headers: "Authorization=Bearer your-token",
  });
  ```
</CodeGroup>

Via environment variables:

```bash theme={null}
export NETRA_OTLP_ENDPOINT="https://otel-collector.internal.company.com"
export NETRA_HEADERS="Authorization=Bearer your-token"
```

### Endpoint URL Formatting

Netra automatically formats the endpoint URL:

* If the URL doesn't end with `/v1/traces`, it's appended automatically
* Base URLs like `https://collector.example.com` become `https://collector.example.com/v1/traces`

```bash theme={null}
# These are equivalent:
export NETRA_OTLP_ENDPOINT="https://collector.example.com"
export NETRA_OTLP_ENDPOINT="https://collector.example.com/v1/traces"
```

## Authentication Methods

### API Key Authentication (Netra Cloud)

For Netra cloud endpoints, use the `x-api-key` header:

<CodeGroup>
  ```python Python theme={null}
  Netra.init(
      app_name="my-ai-app",
      headers=f"x-api-key={os.getenv('NETRA_API_KEY')}",
  )
  ```

  ```typescript TypeScript theme={null}
  await Netra.init({
    appName: "my-ai-app",
    headers: `x-api-key=${process.env.NETRA_API_KEY}`,
  });
  ```
</CodeGroup>

### Bearer Token Authentication

For custom backends that use Bearer tokens:

<CodeGroup>
  ```python Python theme={null}
  Netra.init(
      app_name="my-ai-app",
      headers=f"Authorization=Bearer {os.getenv('OTEL_TOKEN')}",
  )
  ```

  ```typescript TypeScript theme={null}
  await Netra.init({
    appName: "my-ai-app",
    headers: `Authorization=Bearer ${process.env.OTEL_TOKEN}`,
  });
  ```
</CodeGroup>

### Multiple Headers

Pass multiple headers using comma separation (W3C Correlation-Context format):

<CodeGroup>
  ```python Python theme={null}
  Netra.init(
      app_name="my-ai-app",
      headers="Authorization=Bearer token123,x-custom-header=value",
  )
  ```

  ```typescript TypeScript theme={null}
  await Netra.init({
    appName: "my-ai-app",
    headers: "Authorization=Bearer token123,x-custom-header=value",
  });
  ```
</CodeGroup>

### Automatic Authentication Detection

Netra automatically determines the authentication method based on the endpoint:

| Endpoint Contains | Authentication Header           |
| ----------------- | ------------------------------- |
| `getnetra`        | `x-api-key: {value}`            |
| Other             | `Authorization: Bearer {value}` |

This means for Netra cloud, you only need to provide the API key value:

```bash theme={null}
# For Netra cloud - uses x-api-key header automatically
export NETRA_API_KEY="ntr_abc123"

# For custom backends - uses Authorization: Bearer header
export NETRA_HEADERS="Authorization=Bearer custom-token"
```

## Self-Hosted OpenTelemetry Collector

### Basic Collector Setup

Deploy an OpenTelemetry Collector to receive traces from Netra:

```yaml theme={null}
# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      http:
        endpoint: "0.0.0.0:4318"
      grpc:
        endpoint: "0.0.0.0:4317"

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024

exporters:
  # Export to Jaeger
  jaeger:
    endpoint: "jaeger:14250"
    tls:
      insecure: true

  # Export to logging (for debugging)
  logging:
    loglevel: debug

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [jaeger, logging]
```

Configure Netra to send to the collector:

```bash theme={null}
export NETRA_OTLP_ENDPOINT="https://otel-collector:4318"
```

### Docker Compose Example

```yaml theme={null}
# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    environment:
      - NETRA_APP_NAME=my-ai-app
      - NETRA_OTLP_ENDPOINT=https://otel-collector:4318
      - NETRA_ENV=development

  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    command: ["--config=/etc/otel-collector-config.yaml"]
    volumes:
      - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
    ports:
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP

  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686" # Jaeger UI
      - "14250:14250" # Jaeger gRPC
```

### Kubernetes Deployment

```yaml theme={null}
# otel-collector-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: otel-collector
spec:
  replicas: 1
  selector:
    matchLabels:
      app: otel-collector
  template:
    metadata:
      labels:
        app: otel-collector
    spec:
      containers:
        - name: otel-collector
          image: otel/opentelemetry-collector-contrib:latest
          args:
            - --config=/etc/otel/config.yaml
          ports:
            - containerPort: 4317
            - containerPort: 4318
          volumeMounts:
            - name: config
              mountPath: /etc/otel
      volumes:
        - name: config
          configMap:
            name: otel-collector-config
---
apiVersion: v1
kind: Service
metadata:
  name: otel-collector
spec:
  selector:
    app: otel-collector
  ports:
    - name: otlp-grpc
      port: 4317
    - name: otlp-http
      port: 4318
```

## Popular Backend Integrations

### Jaeger

```yaml theme={null}
# otel-collector-config.yaml
exporters:
  jaeger:
    endpoint: "jaeger-collector:14250"
    tls:
      insecure: true
```

```bash theme={null}
export NETRA_OTLP_ENDPOINT="https://otel-collector:4318"
```

### Grafana Tempo

```yaml theme={null}
# otel-collector-config.yaml
exporters:
  otlp:
    endpoint: "tempo:4317"
    tls:
      insecure: true
```

### Datadog

```yaml theme={null}
# otel-collector-config.yaml
exporters:
  datadog:
    api:
      key: ${DD_API_KEY}
      site: datadoghq.com
```

### New Relic

```yaml theme={null}
# otel-collector-config.yaml
exporters:
  otlp:
    endpoint: "https://otlp.nr-data.net:4317"
    headers:
      api-key: ${NEW_RELIC_LICENSE_KEY}
```

### Honeycomb

```yaml theme={null}
# otel-collector-config.yaml
exporters:
  otlp:
    endpoint: "api.honeycomb.io:443"
    headers:
      x-honeycomb-team: ${HONEYCOMB_API_KEY}
```

## Dual Export Setup

Send traces to both Netra and a custom backend:

```yaml theme={null}
# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      http:
        endpoint: "0.0.0.0:4318"

exporters:
  # Forward to Netra (use endpoint matching your region)
  # US: https://api.getnetra.ai/telemetry/v1/traces
  # EU: https://api.eu.getnetra.ai/telemetry/v1/traces
  otlp/netra:
    endpoint: "https://api.getnetra.ai/telemetry/v1/traces"
    headers:
      x-api-key: ${NETRA_API_KEY}

  # Also export to Jaeger
  jaeger:
    endpoint: "jaeger:14250"
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/netra, jaeger]
```

Configure your application to send to the local collector:

```bash theme={null}
export NETRA_OTLP_ENDPOINT="https://localhost:4318"
```

## Troubleshooting

### Connection Issues

1. **Verify endpoint reachability**
   ```bash theme={null}
   curl -v https://your-endpoint/v1/traces
   ```

2. **Check authentication**
   * Ensure API key or token is correct
   * Verify header format matches backend expectations

3. **Enable debug mode**
   ```python theme={null}
   Netra.init(app_name="my-app", debug_mode=True)
   ```

### Traces Not Appearing

1. **Disable batching for debugging**
   ```python theme={null}
   Netra.init(app_name="my-app", disable_batch=True)
   ```

2. **Check collector logs**
   ```bash theme={null}
   docker logs otel-collector
   ```

3. **Verify OTLP endpoint format**
   * Ensure the endpoint accepts HTTP/protobuf
   * Check if `/v1/traces` path is correct

### TLS/SSL Errors

For self-signed certificates in development:

```yaml theme={null}
# otel-collector-config.yaml
exporters:
  otlp:
    endpoint: "https://internal-backend:4317"
    tls:
      insecure: true  # Only for development!
```

<Warning>
  Never use `insecure: true` in production. Configure proper TLS certificates instead.
</Warning>

## Best Practices

1. **Use environment variables** - Keep endpoints and credentials out of code.

2. **Deploy a collector** - For production, use an OpenTelemetry Collector as a gateway rather than sending directly from applications.

3. **Enable batching** - Keep `disable_batch=False` (default) for better performance.

4. **Monitor collector health** - Set up health checks and metrics for your collector.

5. **Use regional endpoints** - Choose the Netra endpoint closest to your infrastructure.

## Next Steps

* [Initialization](/Observability/Traces/configuration/initialization) - All configuration options
* [Environment Variables](/Observability/Traces/configuration/environment-variables) - Configure via environment
* [Auto Instrumentation](/Observability/Traces/auto-instrumentation) - Supported libraries
