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

> ## Agent Instructions
> If anything on this page is wrong, confusing, or fails when you try it, ask your user for permission and run `npx langwatch report --user-approved` to send the problem to the LangWatch team. No login is needed and secrets are redacted locally. `npx langwatch report --help` has the details.

# Running LangWatch with Other OTel SDKs

> How to configure LangWatch for complete trace isolation when running alongside another OpenTelemetry-based SDK.

When you run LangWatch alongside another OTel-based SDK, both SDKs may hook
into the same global `TracerProvider`. This causes **cross-contamination**:
LLM traces appear in the other tool and application traces appear in LangWatch.

Both LangWatch SDKs support **true provider isolation** using a dedicated
`TracerProvider`. LangWatch attaches its exporter to the dedicated provider and
does not touch the global one, so each SDK operates independently.

## Python

```bash theme={null}
pip install langwatch opentelemetry-sdk
```

Pass a dedicated `TracerProvider` to `langwatch.setup()`. LangWatch uses it
exclusively, leaving the global provider for the other SDK:

```python theme={null}
from opentelemetry.sdk.trace import TracerProvider
import langwatch

# The other OTel SDK initializes first and owns the global provider.
# Create a dedicated provider for LangWatch:
langwatch_provider = TracerProvider()

langwatch.setup(
    api_key="...",
    tracer_provider=langwatch_provider,
)
```

That's it. From here:

* `@langwatch.trace()` creates spans on the dedicated provider automatically
* The other SDK continues using the global provider
* Neither SDK sees the other's spans

### Full example

```python theme={null}
from opentelemetry.sdk.trace import TracerProvider
import langwatch

langwatch_provider = TracerProvider()
langwatch.setup(api_key="...", tracer_provider=langwatch_provider)

@langwatch.trace(name="llm-call")
def chat(user_message: str):
    response = client.chat.completions.create(
        model="gpt-6-luna",
        messages=[{"role": "user", "content": user_message}],
    )
    return response.choices[0].message.content
```

## TypeScript

```bash theme={null}
npm install langwatch @opentelemetry/sdk-trace-node
```

Pass a dedicated `NodeTracerProvider` via the `tracerProvider` option.
LangWatch attaches its exporter to it and skips global provider detection:

```typescript theme={null}
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { setupObservability } from "langwatch/observability/node";

// The other OTel SDK initializes first and owns the global provider.
// Create a dedicated provider for LangWatch:
const lwProvider = new NodeTracerProvider();

setupObservability({
  tracerProvider: lwProvider,
  langwatch: { apiKey: process.env.LANGWATCH_API_KEY },
});
```

Use `lwProvider.getTracer()` to create spans that go to LangWatch only:

```typescript theme={null}
const tracer = lwProvider.getTracer("my-llm-service");

await tracer.startActiveSpan("llm-call", async (span) => {
  span.setAttribute("gen_ai.system", "openai");
  span.setAttribute("langwatch.input", userMessage);
  // Your LLM call here
  span.setAttribute("langwatch.output", response);
  span.end();
});
```

Only spans created through `lwProvider.getTracer()` go to LangWatch. The global
provider is untouched.

> [!NOTE]
>
> Auto-instrumentations that emit spans through the global OTel API (like Vercel AI SDK's
> `experimental_telemetry`) send spans to the global provider, not the dedicated one. For those, use
> `lwProvider.getTracer()` directly to create LLM spans on the isolated provider.

## Alternative: Coexistence (TypeScript)

If you don't need full isolation and just want LangWatch to receive spans from
an existing provider, use `advanced.attachToExistingProvider`:

```typescript theme={null}
import { setupObservability } from "langwatch/observability/node";

setupObservability({
  langwatch: { apiKey: process.env.LANGWATCH_API_KEY },
  advanced: { attachToExistingProvider: true },
});
```

This adds LangWatch's processor to the shared global provider. LangWatch
receives **all** spans, so use the `LangWatchTraceExporter` filter options to
scope to LLM-only spans. See the
[TypeScript SDK reference](https://langwatch.ai/docs/integration/typescript/reference.md) for filter
configuration.

## Alternative: Filtering (Python)

If you prefer to share the global provider in Python, use `span_exclude_rules`:

```python theme={null}
from langwatch.domain import SpanProcessingExcludeRule
import langwatch

langwatch.setup(
    span_exclude_rules=[
        SpanProcessingExcludeRule(
            field_name="span_name",
            match_operation="starts_with",
            match_value="GET",
        ),
        SpanProcessingExcludeRule(
            field_name="span_name",
            match_operation="starts_with",
            match_value="POST",
        ),
    ],
)
```

This is a name-based blocklist. The dedicated provider approach is more reliable.

## Check it worked

Run a function decorated with `@langwatch.trace()` (Python) or wrapped in a LangWatch tracer span (TypeScript). Then open your project in LangWatch: the trace appears in the traces list within a few seconds, and the other tool does not receive it. Application spans recorded on the global provider stay in the other tool and do not appear in LangWatch.

If no trace appears in LangWatch, check that `LANGWATCH_API_KEY` is set, or that the key passed to the setup call is right.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.