Skip to main content

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.

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 — each SDK operates independently.

Python

Pass a dedicated TracerProvider to langwatch.setup(). LangWatch uses it exclusively, leaving the global provider for the other SDK:
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

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-4.1-nano",
        messages=[{"role": "user", "content": user_message}],
    )
    return response.choices[0].message.content

TypeScript

Pass a dedicated NodeTracerProvider via the tracerProvider option. LangWatch attaches its exporter to it and skips global provider detection:
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:
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.
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:
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 — use the LangWatchTraceExporter filter options to scope to LLM-only spans. See the TypeScript SDK reference for filter configuration.

Alternative: Filtering (Python)

If you prefer to share the global provider in Python, use span_exclude_rules:
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.