---
title: "Direct OTEL Trace Export"
description: "Export standard OTLP/HTTP traces directly to Judgment."
sidebar:
  label: "Direct OTEL"
seo:
  title: "Direct OTEL Trace Export to Judgment | Integration Docs"
  description: "Export Direct OTEL traces to Judgment so teams can inspect agent behavior, run judges, and monitor production regressions."
---

Use **Direct OTEL** when your application, framework, or collector already
exports OpenTelemetry traces. Judgment accepts standard OTLP/HTTP protobuf
trace payloads, so you can send spans directly without a Judgment SDK wrapper.

## Connection Details

| Setting  | Value                                           |
| -------- | ----------------------------------------------- |
| Endpoint | `https://api.judgmentlabs.ai/otel/v1/traces`    |
| Protocol | `OTLP HTTP/protobuf`                            |
| Header   | `Authorization: Bearer <JUDGMENT_API_KEY>`      |
| Header   | `X-Organization-Id: <JUDGMENT_ORG_ID>`          |
| Header   | `X-Project-Id: <JUDGMENT_PROJECT_ID>`           |

See [Authentication](/documentation/reference/authentication) for the identity
and header contract, and [Project routing](/documentation/reference/project-routing)
for the difference between SDK project names and the project ID required here.

> **Tip**
>
> To find `JUDGMENT_ORG_ID` or `JUDGMENT_PROJECT_ID`, open the organization or
> project in the Judgment app and copy the ID from the URL, or press `Ctrl-K`
> and search for the organization ID or project ID shortcut.

## Examples

**Python**

```bash
pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
```

```python title="direct_otel.py"
import os

from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

provider = TracerProvider(
    resource=Resource.create({"service.name": "my-service"})
)

provider.add_span_processor(
    BatchSpanProcessor(
        OTLPSpanExporter(
            endpoint="https://api.judgmentlabs.ai/otel/v1/traces",
            headers={
                "Authorization": f"Bearer {os.environ['JUDGMENT_API_KEY']}",
                "X-Organization-Id": os.environ["JUDGMENT_ORG_ID"],
                "X-Project-Id": os.environ["JUDGMENT_PROJECT_ID"],
            },
        )
    )
)

trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("direct_otel_example"):
    pass

provider.force_flush()
```

**TypeScript**

```bash
npm install @opentelemetry/api @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/sdk-trace-node
```

```ts title="direct-otel.ts"
import { trace } from "@opentelemetry/api";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { resourceFromAttributes } from "@opentelemetry/resources";
import {
  BatchSpanProcessor,
  NodeTracerProvider,
} from "@opentelemetry/sdk-trace-node";

const exporter = new OTLPTraceExporter({
  url: "https://api.judgmentlabs.ai/otel/v1/traces",
  headers: {
    Authorization: `Bearer ${process.env.JUDGMENT_API_KEY}`,
    "X-Organization-Id": process.env.JUDGMENT_ORG_ID ?? "",
    "X-Project-Id": process.env.JUDGMENT_PROJECT_ID ?? "",
  },
});

const provider = new NodeTracerProvider({
  resource: resourceFromAttributes({
    "service.name": "my-service",
  }),
  spanProcessors: [new BatchSpanProcessor(exporter)],
});

provider.register();

const tracer = trace.getTracer("direct-otel-example");
const span = tracer.startSpan("direct_otel_example");
span.end();

await provider.forceFlush();
```

**Go**

```bash
go get go.opentelemetry.io/otel go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp go.opentelemetry.io/otel/sdk
```

```go title="direct_otel.go"
package main

import (
	"context"
	"os"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

func main() {
	ctx := context.Background()

	exporter, err := otlptracehttp.New(
		ctx,
		otlptracehttp.WithEndpointURL("https://api.judgmentlabs.ai/otel/v1/traces"),
		otlptracehttp.WithHeaders(map[string]string{
			"Authorization":     "Bearer " + os.Getenv("JUDGMENT_API_KEY"),
			"X-Organization-Id": os.Getenv("JUDGMENT_ORG_ID"),
			"X-Project-Id":      os.Getenv("JUDGMENT_PROJECT_ID"),
		}),
	)
	if err != nil {
		panic(err)
	}

	provider := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(resource.NewWithAttributes(
			"",
			attribute.String("service.name", "my-service"),
		)),
	)
	defer func() {
		if err := provider.Shutdown(ctx); err != nil {
			panic(err)
		}
	}()

	otel.SetTracerProvider(provider)
	tracer := otel.Tracer("direct-otel-example")

	_, span := tracer.Start(ctx, "direct_otel_example")
	span.End()
}
```

> **Info**
>
> Use environment variables or secret management for these values. Do not
> publish real organization or project IDs in public docs or client-side code.

## Related pages

- [Trace conventions](/documentation/reference/trace-conventions) for root,
  resource, and context semantics
- [Attribute keys](/documentation/tracing/attribute-keys) for structured
  Judgment span fields
- [Configure attribute mappers](/documentation/tracing/attribute-mappers) when
  existing instrumentation uses different source keys
