---
title: "Keep your existing observability tool"
description: "Add Judgment as a second destination alongside Logfire, LangSmith, Braintrust or Langfuse."
sidebar:
  label: "Keep your existing tool"
seo:
  title: "Keep your existing observability tool | Judgment Docs"
  description: "Add Judgment as a second destination alongside Logfire, LangSmith, Braintrust or Langfuse."
---

All four tools build on OpenTelemetry, so Judgment can be one more span processor on the same tracer provider, and both tools get the same spans. This doesn't import traces you already stored in another tool; if you need history moved over, [contact support](/documentation/start/get-help).

## What Judgment reads from each tool

| Tool | How you add Judgment | What Judgment's ingest maps from the tool's own attributes |
|---|---|---|
| Logfire | `additional_span_processors` in `logfire.configure()` | `logfire.msg` becomes the span name |
| LangSmith | LangSmith OpenTelemetry mode on a shared provider | `langsmith.span.kind` becomes the span kind |
| Braintrust | `BraintrustSpanProcessor` next to Judgment's on a shared provider | model, provider, prompt and completion tokens, cost |
| Langfuse | A shared provider passed to `Langfuse(tracer_provider=...)` | Nothing. Judgment has no Langfuse mapper, so Langfuse is documented here as a destination only |

Standard OpenTelemetry GenAI attributes (`gen_ai.*`) and OpenInference attributes map the same way no matter which tool created the span. If a field you need isn't mapped, add a mapper: see [Attribute keys and mappers](/documentation/reference/attribute-keys-and-mappers).

## Build the Judgment span processor

Each example below adds this processor. It's a standard OTLP exporter, so it needs the project ID rather than the name; see [Send OTLP directly](/documentation/connect/integrations/send-otlp-directly) for where to find it.

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

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

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


def create_judgment_processor() -> BatchSpanProcessor:
    return 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"],
            },
        )
    )
```

Both tools now receive the same data, so apply the same scrubbing and sampling policy you already use.

## Logfire

```python
import logfire
from judgment_otlp import create_judgment_processor

logfire.configure(
    service_name="lunch-order-agent",
    additional_span_processors=[create_judgment_processor()],
)
logfire.instrument_openai()
```

If `logfire.configure()` rejects `additional_span_processors`, upgrade `logfire`.

## LangSmith

LangSmith's OpenTelemetry mode uses the global provider when one is set. Set one that includes Judgment, and leave `LANGSMITH_OTEL_ONLY` unset so runs still go to LangSmith too. This needs `langsmith[otel]`.

```python
import os

from judgment_otlp import create_judgment_processor
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider

os.environ["LANGSMITH_OTEL_ENABLED"] = "true"
os.environ["LANGSMITH_TRACING"] = "true"

provider = TracerProvider()
provider.add_span_processor(create_judgment_processor())
trace.set_tracer_provider(provider)
```

Run this before your first chain or graph runs.

## Braintrust

Install `braintrust[otel]`.

```python
from braintrust.otel import BraintrustSpanProcessor
from judgment_otlp import create_judgment_processor
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider

provider = TracerProvider()
provider.add_span_processor(BraintrustSpanProcessor(parent="project_name:lunch-order-agent"))
provider.add_span_processor(create_judgment_processor())
trace.set_tracer_provider(provider)
```

## Langfuse

Langfuse's Python SDK v3 and later accepts a tracer provider. Add Judgment to it and keep your Langfuse instrumentation as it is.

```python
import os

from judgment_otlp import create_judgment_processor
from langfuse import Langfuse
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider

provider = TracerProvider()
provider.add_span_processor(create_judgment_processor())
trace.set_tracer_provider(provider)

langfuse = Langfuse(
    public_key=os.environ["LANGFUSE_PUBLIC_KEY"],
    secret_key=os.environ["LANGFUSE_SECRET_KEY"],
    tracer_provider=provider,
)
```

> **Tip**
>
> If your traces already pass through an OpenTelemetry Collector, add Judgment as one more exporter there instead of changing application code. The Collector config is on [Send OTLP directly](/documentation/connect/integrations/send-otlp-directly).
