Langflow Tracing and Observability Integrations: Complete Guide to LangSmith, LangFuse, and More
Langflow natively supports seven observability platforms—including LangSmith, LangFuse, LangWatch, Opik, Arize Phoenix, and Traceloop—through a modular tracing service that automatically activates when specific environment variables are present.
The langflow-ai/langflow repository implements a comprehensive tracing and observability system in src/backend/base/langflow/services/tracing/ that forwards execution data from flow runs to third-party monitoring backends. This architecture requires no application code changes; integrations activate automatically based on environment configuration, using an abstract BaseTracer contract to standardize telemetry collection across diverse platforms.
Supported Observability Integrations
Langflow's TracingService detects and initializes tracer implementations based on the presence of vendor-specific environment variables. Each integration implements the BaseTracer interface defined in src/backend/base/langflow/services/tracing/base.py.
LangSmith
Activation: Set LANGCHAIN_API_KEY. Langflow automatically injects LANGCHAIN_TRACING_V2="true".
Implementation: The LangSmithTracer class in src/backend/base/langflow/services/tracing/langsmith.py constructs run trees and component spans using the LangSmith client. It converts internal Langflow Message and Data objects to LangChain-compatible types via _convert_to_langchain_types.
LangFuse
Activation: Define LANGFUSE_SECRET_KEY, LANGFUSE_PUBLIC_KEY, and LANGFUSE_HOST.
Implementation: LangFuseTracer (located in src/backend/base/langflow/services/tracing/langfuse.py) creates hierarchical spans with inputs, outputs, metadata, and error information using self.trace.span() calls.
LangWatch
Activation: Set LANGWATCH_API_KEY and optionally LANGWATCH_ENDPOINT.
Implementation: The LangWatchTracer in src/backend/base/langflow/services/tracing/langwatch.py exports OpenTelemetry spans to LangWatch’s OTLP endpoint, converting data via _convert_to_langwatch_types.
Opik
Activation: Configure OPIK_PROJECT_NAME and ensure valid Opik client configuration is present.
Implementation: OpikTracer (src/backend/base/langflow/services/tracing/opik.py) manages trace and span objects with distributed-header propagation support.
Arize Phoenix
Activation: Provide ARIZE_PHOENIX_API_KEY and ARIZE_PHOENIX_ENDPOINT.
Implementation: The ArizePhoenixTracer in src/backend/base/langflow/services/tracing/arize_phoenix.py implements a span processor that forwards telemetry to Arize Phoenix endpoints.
Traceloop
Activation: Set TRACEELOOP_API_KEY.
Implementation: TraceloopTracer (src/backend/base/langflow/services/tracing/traceloop.py) provides automatic LangChain-compatible instrumentation via the Traceloop SDK.
Minimal LFX Tracing
Fallback behavior: When deactivate_tracing is disabled and no external variables are set, the system uses a minimal in-process tracer defined in src/lfx/src/lfx/services/tracing/service.py for local log entries.
Internal Architecture and Data Flow
The BaseTracer Contract
All integrations inherit from BaseTracer in src/backend/base/langflow/services/tracing/base.py, which defines the interface for add_trace, set_outputs, end_trace, and get_langchain_callbacks. This abstraction allows TracingService to remain agnostic to specific vendor implementations.
TraceContext and Async Processing
When a graph run starts, TracingService.create_trace_context() instantiates a TraceContext object containing:
run_id,run_name,user_id,session_id- A per-run async queue (
traces_queue) - A dictionary of active tracers
The service spawns a background _trace_worker that drains the queue sequentially, ensuring network I/O does not block graph execution. All tracer method calls are enqueued via TraceContext.traces_queue.put_nowait().
Lazy Initialization Pattern
The TracingService._start() method in src/backend/base/langflow/services/tracing/service.py lazily instantiates tracers through helper methods like _initialize_langsmith_tracer() and _initialize_langfuse_tracer(). Each helper checks for required environment variables and SDK availability:
def _initialize_langsmith_tracer(self, ctx):
if not os.getenv("LANGCHAIN_API_KEY"):
return
ctx.tracers["langsmith"] = _get_langsmith_tracer()(
trace_name=ctx.run_name,
trace_type="chain",
project_name=ctx.project_name,
trace_id=ctx.run_id,
)
If import or authentication fails, the tracer sets _ready = False and is silently omitted from the active tracer list.
Metadata Conversion
Concrete tracers implement conversion helpers to transform Langflow internal types:
_convert_to_langchain_types()for LangSmith compatibility_convert_to_opik_types()for Opik traces_convert_to_langwatch_types()for LangWatch spans
These methods recursively process Message, Data, and arbitrary Python objects into JSON-serializable dictionaries or vendor-specific message formats.
Configuring Tracing Integrations
Enable observability by setting environment variables before starting Langflow. No code changes are required.
Enabling LangSmith
export LANGCHAIN_API_KEY="sk-your-key"
# LANGCHAIN_TRACING_V2 is automatically set by Langflow
Enabling LangFuse
export LANGFUSE_PUBLIC_KEY="public-key"
export LANGFUSE_SECRET_KEY="secret-key"
export LANGFUSE_HOST="https://cloud.langfuse.com"
Enabling LangWatch
export LANGWATCH_API_KEY="your-api-key"
export LANGWATCH_ENDPOINT="https://api.langwatch.com" # Optional
Programmatic Tracing API
For custom instrumentation within components, use the TracingService directly.
Manual Trace Context Management
from langflow.services.tracing.service import TracingService
from uuid import uuid4
# Initialize service with settings that do not deactivate tracing
tracing = TracingService(settings_service=my_settings)
# Start a run session
run_id = uuid4()
await tracing.start_tracers(
run_id=run_id,
run_name="example-run",
user_id="user-123",
session_id="sess-abc",
project_name="demo-proj",
)
# Trace component execution
async with tracing.trace_component(
component=my_component,
trace_name="my-component",
inputs={"query": "user input"},
) as ctx:
result = await my_component.run()
tracing.set_outputs("my-component", {"result": result})
Adding Custom Logs
import time
tracing.add_log("my-component", {
"event": "processing_started",
"timestamp": time.time(),
"metadata": {"batch_size": 10}
})
Error Handling
Errors are automatically captured via _error_to_string() methods that serialize stack traces into the trace metadata before end_trace() finalizes the span.
Summary
- Langflow provides seven production-ready observability integrations through a unified tracing architecture in
src/backend/base/langflow/services/tracing/. - The modular design uses
BaseTracerabstractions and lazy initialization based on environment variable detection. - Zero-code configuration activates tracers like LangSmith (
LANGCHAIN_API_KEY) and LangFuse (LANGFUSE_SECRET_KEY) automatically. - Async queue processing ensures telemetry export does not block flow execution, managed by
TraceContextand_trace_worker. - Metadata conversion helpers normalize Langflow's internal
MessageandDatatypes to vendor-specific formats. - Programmatic access via
trace_component()context managers allows custom instrumentation within component logic.
Frequently Asked Questions
How do I enable LangSmith tracing in Langflow?
Set the LANGCHAIN_API_KEY environment variable. Langflow automatically detects this in TracingService._initialize_langsmith_tracer() and instantiates the LangSmithTracer class. The system also injects LANGCHAIN_TRACING_V2="true" automatically. No code changes are required within your flows.
What is the difference between LangSmith and LangFuse integrations?
LangSmith focuses on LangChain-compatible run trees and uses _convert_to_langchain_types() for data serialization, requiring only LANGCHAIN_API_KEY. LangFuse provides hierarchical span management with explicit input/output tracking via self.trace.span() calls, requiring three variables: LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, and LANGFUSE_HOST. LangFuse also captures more granular metadata by default.
Can I use multiple tracing providers simultaneously?
Yes. TracingService maintains a dictionary of active tracers in TraceContext.tracers. If you set environment variables for multiple providers (e.g., both LangSmith and LangFuse), both tracers initialize and receive identical trace data through the async queue. Each tracer processes the data independently according to its vendor-specific conversion logic.
Where are the tracer implementations located in the codebase?
Concrete implementations reside in src/backend/base/langflow/services/tracing/:
- LangSmith:
langsmith.py - LangFuse:
langfuse.py - LangWatch:
langwatch.py - Opik:
opik.py - Arize Phoenix:
arize_phoenix.py - Traceloop:
traceloop.py
The abstract contract is defined in base.py, while the central orchestration logic lives in service.py.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →