Metadata enriches your traces with contextual information — who made the request, which conversation it belongs to, and any custom data relevant to your application. Labels help you categorize and filter traces in the dashboard.
This guide provides a unified reference for sending metadata across all integration methods. For SDK-specific details, see the tutorials linked below.
Quick Reference
Concept OTEL Attribute REST API Description Thread/Conversation gen_ai.conversation.idmetadata.thread_idGroups messages in a conversation User ID langwatch.user.idmetadata.user_idIdentifies the end user Customer ID langwatch.customer.idmetadata.customer_idYour platform’s customer/tenant Labels langwatch.labelsmetadata.labelsCategorization tags Custom Metadata metadata attributemetadata.*Any additional context
SDK Examples
For detailed SDK-specific tutorials, see:
import { setupObservability } from "langwatch/observability/node" ;
import { getLangWatchTracer } from "langwatch" ;
setupObservability ();
const tracer = getLangWatchTracer ( "my-service" );
async function handleUserMessage ( userId : string , conversationId : string ) {
return await tracer . withActiveSpan ( "HandleMessage" , async ( span ) => {
// Thread/conversation ID (OTEL semconv)
span . setAttribute ( "gen_ai.conversation.id" , conversationId );
// User and customer identification
span . setAttribute ( "langwatch.user.id" , userId );
span . setAttribute ( "langwatch.customer.id" , "tenant-123" );
// Labels for filtering (JSON array)
span . setAttribute ( "langwatch.labels" , JSON . stringify ([ "production" , "premium-user" ]));
// Custom metadata (JSON object)
span . setAttribute ( "metadata" , JSON . stringify ({
feature_flags: [ "new-ui" , "beta-model" ],
request_source: "mobile-ios"
}));
// Your application logic...
});
}
Raw OpenTelemetry
If you’re using vanilla OpenTelemetry without the LangWatch SDK:
import { trace } from "@opentelemetry/api" ;
const tracer = trace . getTracer ( "my-service" );
tracer . startActiveSpan ( "operation" , ( span ) => {
// OTEL semconv for conversation/thread
span . setAttribute ( "gen_ai.conversation.id" , "conv-456" );
// LangWatch-specific attributes
span . setAttribute ( "langwatch.user.id" , "user-123" );
span . setAttribute ( "langwatch.customer.id" , "customer-789" );
span . setAttribute ( "langwatch.labels" , JSON . stringify ([ "urgent" , "support" ]));
// Custom metadata as JSON string
span . setAttribute ( "metadata" , JSON . stringify ({
priority: "high" ,
department: "engineering"
}));
// ... your code ...
span . end ();
});
Exporter configuration:
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http" ;
const exporter = new OTLPTraceExporter ({
url: "https://app.langwatch.ai/api/otel/v1/traces" ,
headers: {
Authorization: `Bearer ${ process . env . LANGWATCH_API_KEY } ` ,
},
});
The OTEL endpoint is /api/otel/v1/traces (not /v1/traces).
REST API
Send traces directly via HTTP. See REST API for full details.
curl -X POST "https://app.langwatch.ai/api/collector" \
-H "X-Auth-Token: $LANGWATCH_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"trace_id": "trace-123",
"spans": [
{
"type": "llm",
"span_id": "span-456",
"name": "chat-completion",
"model": "gpt-4",
"input": {"type": "text", "value": "Hello"},
"output": {"type": "text", "value": "Hi there!"},
"timestamps": {
"started_at": 1699900000000,
"finished_at": 1699900001000
}
}
],
"metadata": {
"user_id": "user-123",
"thread_id": "conversation-456",
"customer_id": "customer-789",
"labels": ["production", "premium"],
"any_custom_field": "any value"
}
}'
Reserved vs Custom Fields
In the REST API metadata object:
Field Type Description user_idstring End user identifier thread_idstring Conversation/session ID customer_idstring Your tenant/customer ID labelsstring[] Categorization tags other keys any Stored as custom metadata
Best Practices
Always set user_id Required for user-level analytics and filtering by specific users.
Use thread_id for conversations Groups related messages together. Essential for chatbots and multi-turn interactions.
Labels for categorization Use consistent labels like production, staging, support for filtering.
Custom metadata for context Add any relevant context: feature flags, A/B variants, request sources.
What You Get
Once traces include metadata:
Filter by user — Find all traces for a specific user
View conversations — See all messages in a thread grouped together
Filter by labels — Quickly filter to specific categories
Search custom fields — Find traces by any custom metadata value
User analytics — View per-user metrics and patterns