Skip to main content

What is Metadata?

Metadata allows you to attach custom context to each LLM call. This additional information helps you:
  • Debug issues - Add request IDs, user IDs, and error context
  • Filter traces - Find specific calls by feature, environment, or user
  • Analyze patterns - Group traces by tenant, version, or experiment
  • Track business metrics - Associate calls with revenue, user segments, etc.

Use Cases

User Context

Track which users make which callsuser_id, tenant_id, organization

Feature Tracking

Identify which features are being usedfeature, experiment_id, variant

Environment Info

Separate different deployment environmentsenvironment, version, build_id

Request Tracing

Correlate with other systemsrequest_id, trace_id, span_id

Business Context

Track business metricsplan_type, revenue, priority

Debugging

Add context for troubleshootingerror_type, retry_count, source

Vercel AI SDK

Pass metadata via providerOptions.observ.metadata:
import { generateText } from "ai";

// Attach custom metadata to traces
const result = await generateText({
  model, // Your wrapped model
  prompt: "Explain React hooks",
  providerOptions: {
    observ: {
      metadata: {
        user_id: "user_123",
        feature: "documentation",
        version: "2.0",
      },
    },
  },
});

// Metadata appears in your Observ dashboard
// for filtering, debugging, and analytics

Provider SDKs

Chain .withMetadata() (TypeScript) or .with_metadata() (Python) to attach data.

Basic Example

const response = await wrappedClient.messages
  .withMetadata({
    user_id: "user_123",
    feature: "chat",
    version: "1.0.0"
  })
  .create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello!" }],
  });

All Providers

Metadata works with all supported providers:
const response = await wrappedClient.messages
  .withMetadata({
    user_id: "user_123",
    feature: "chat",
    environment: "production",
  })
  .create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello!" }],
  });
const response = await wrappedClient.chat.completions
  .withMetadata({
    user_id: "user_123",
    feature: "chat",
  })
  .create({
    model: "gpt-4",
    messages: [{ role: "user", content: "Hello!" }],
  });
const response = await wrappedClient.chat.completions
  .withMetadata({
    user_id: "user_123",
    feature: "chat",
  })
  .create({
    model: "mistral-large-latest",
    messages: [{ role: "user", content: "Hello!" }],
  });
const response = await wrappedClient.chat.completions
  .withMetadata({
    user_id: "user_123",
    feature: "chat",
  })
  .create({
    model: "grok-beta",
    messages: [{ role: "user", content: "Hello!" }],
  });
const response = await wrappedClient.chat.completions
  .withMetadata({
    user_id: "user_123",
    feature: "chat",
  })
  .create({
    model: "anthropic/claude-3.5-sonnet",
    messages: [{ role: "user", content: "Hello!" }],
  });

Common Metadata Fields

Here are commonly used metadata fields and their purposes:
{
  "user_id": "user_123",
  "feature": "chat",
  "environment": "production",
  "version": "1.0.0",
  "request_id": "req_abc123",
  "tenant_id": "tenant_456"
}
Purpose: Track which user made the requestExample values: "user_123", "customer_abc", "anonymous_xyz"Useful for debugging user-specific issues and analyzing usage patterns.
Purpose: Identify which feature or flow triggered the callExample values: "chat", "documentation", "support", "autocomplete"Useful for feature analytics and A/B testing.
Purpose: Separate traces by deployment environmentExample values: "production", "staging", "development", "test"Useful for debugging environment-specific issues. Also available as a top-level configuration option.
Purpose: Track which version of your app made the callExample values: "1.0.0", "2.3.1", "2024-01-08"Useful for identifying regressions and comparing versions.
Purpose: Correlate with your application’s request tracingExample values: "req_abc123", "trace_xyz789"Useful for end-to-end debugging across systems.
Purpose: Track multi-tenant applicationsExample values: "tenant_456", "org_acme", "company_123"Useful for per-tenant analytics and billing.

Best Practices

Standardize your metadata fields across your application for easier filtering and analysis.
// Good - consistent naming
{ user_id: "123", feature: "chat" }

// Bad - inconsistent naming
{ userId: "123", featureName: "chat" }
Avoid adding PII, passwords, or other sensitive information to metadata.
// Good - anonymized
{ user_id: "user_123" }

// Bad - PII
{ email: "[email protected]", ssn: "123-45-6789" }
Use strings and numbers for metadata values. Avoid complex objects.
// Good - simple values
{ user_id: "123", plan: "pro", count: 5 }

// Bad - complex object
{ user: { id: 123, profile: { ... } } }
Design metadata fields that will be useful for filtering in the dashboard.Common filters: user_id, feature, environment, version, tenant_id

Combining with Sessions

You can use both metadata and session tracking together:
const response = await wrappedClient.messages
  .withSessionId("conversation_abc123")
  .withMetadata({
    user_id: "user_123",
    feature: "chat",
    environment: "production",
  })
  .create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello!" }],
  });

Next Steps

Session Tracking

Group related calls with session IDs

Provider SDKs

Learn about provider SDK integration

Vercel AI SDK

Learn about Vercel AI SDK integration

Dashboard

View your traces and analytics