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

# Custom Metadata

> Attach custom key-value pairs to traces for powerful filtering, debugging, and analytics in your dashboard

## 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

<CardGroup cols={3}>
  <Card title="User Context" icon="user">
    Track which users make which calls

    `user_id`, `tenant_id`, `organization`
  </Card>

  <Card title="Feature Tracking" icon="flag">
    Identify which features are being used

    `feature`, `experiment_id`, `variant`
  </Card>

  <Card title="Environment Info" icon="server">
    Separate different deployment environments

    `environment`, `version`, `build_id`
  </Card>

  <Card title="Request Tracing" icon="link">
    Correlate with other systems

    `request_id`, `trace_id`, `span_id`
  </Card>

  <Card title="Business Context" icon="chart-bar">
    Track business metrics

    `plan_type`, `revenue`, `priority`
  </Card>

  <Card title="Debugging" icon="bug">
    Add context for troubleshooting

    `error_type`, `retry_count`, `source`
  </Card>
</CardGroup>

## Vercel AI SDK

Pass metadata via `providerOptions.observ.metadata`:

```typescript theme={null}
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

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    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!" }],
      });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    response = wrapped_client.messages.with_metadata({
        "user_id": "user_123",
        "feature": "chat",
        "version": "1.0.0"
    }).create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}],
    )
    ```
  </Tab>
</Tabs>

### All Providers

Metadata works with all supported providers:

<Tabs>
  <Tab title="TypeScript">
    <AccordionGroup>
      <Accordion title="Anthropic">
        ```typescript theme={null}
        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!" }],
          });
        ```
      </Accordion>

      <Accordion title="OpenAI">
        ```typescript theme={null}
        const response = await wrappedClient.chat.completions
          .withMetadata({
            user_id: "user_123",
            feature: "chat",
          })
          .create({
            model: "gpt-4",
            messages: [{ role: "user", content: "Hello!" }],
          });
        ```
      </Accordion>

      <Accordion title="Mistral">
        ```typescript theme={null}
        const response = await wrappedClient.chat.completions
          .withMetadata({
            user_id: "user_123",
            feature: "chat",
          })
          .create({
            model: "mistral-large-latest",
            messages: [{ role: "user", content: "Hello!" }],
          });
        ```
      </Accordion>

      <Accordion title="xAI">
        ```typescript theme={null}
        const response = await wrappedClient.chat.completions
          .withMetadata({
            user_id: "user_123",
            feature: "chat",
          })
          .create({
            model: "grok-beta",
            messages: [{ role: "user", content: "Hello!" }],
          });
        ```
      </Accordion>

      <Accordion title="OpenRouter">
        ```typescript theme={null}
        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!" }],
          });
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="Python">
    <AccordionGroup>
      <Accordion title="Anthropic">
        ```python theme={null}
        response = wrapped_client.messages.with_metadata({
            "user_id": "user_123",
            "feature": "chat",
            "environment": "production",
        }).create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            messages=[{"role": "user", "content": "Hello!"}],
        )
        ```
      </Accordion>

      <Accordion title="OpenAI">
        ```python theme={null}
        response = wrapped_client.chat.completions.with_metadata({
            "user_id": "user_123",
            "feature": "chat",
        }).create(
            model="gpt-4",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        ```
      </Accordion>

      <Accordion title="Mistral">
        ```python theme={null}
        response = wrapped_client.chat.completions.with_metadata({
            "user_id": "user_123",
            "feature": "chat",
        }).create(
            model="mistral-large-latest",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        ```
      </Accordion>

      <Accordion title="Google (Gemini)">
        ```python theme={null}
        response = wrapped_model.with_metadata({
            "user_id": "user_123",
            "feature": "chat",
        }).generate_content("Hello!")
        ```
      </Accordion>

      <Accordion title="xAI">
        ```python theme={null}
        response = wrapped_client.chat.completions.with_metadata({
            "user_id": "user_123",
            "feature": "chat",
        }).create(
            model="grok-beta",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        ```
      </Accordion>

      <Accordion title="OpenRouter">
        ```python theme={null}
        response = wrapped_client.chat.completions.with_metadata({
            "user_id": "user_123",
            "feature": "chat",
        }).create(
            model="anthropic/claude-3.5-sonnet",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

## Common Metadata Fields

Here are commonly used metadata fields and their purposes:

<CodeGroup>
  ```json Example Metadata theme={null}
  {
    "user_id": "user_123",
    "feature": "chat",
    "environment": "production",
    "version": "1.0.0",
    "request_id": "req_abc123",
    "tenant_id": "tenant_456"
  }
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="user_id">
    **Purpose:** Track which user made the request

    **Example values:** `"user_123"`, `"customer_abc"`, `"anonymous_xyz"`

    Useful for debugging user-specific issues and analyzing usage patterns.
  </Accordion>

  <Accordion title="feature">
    **Purpose:** Identify which feature or flow triggered the call

    **Example values:** `"chat"`, `"documentation"`, `"support"`, `"autocomplete"`

    Useful for feature analytics and A/B testing.
  </Accordion>

  <Accordion title="environment">
    **Purpose:** Separate traces by deployment environment

    **Example values:** `"production"`, `"staging"`, `"development"`, `"test"`

    Useful for debugging environment-specific issues. Also available as a top-level configuration option.
  </Accordion>

  <Accordion title="version">
    **Purpose:** Track which version of your app made the call

    **Example values:** `"1.0.0"`, `"2.3.1"`, `"2024-01-08"`

    Useful for identifying regressions and comparing versions.
  </Accordion>

  <Accordion title="request_id">
    **Purpose:** Correlate with your application's request tracing

    **Example values:** `"req_abc123"`, `"trace_xyz789"`

    Useful for end-to-end debugging across systems.
  </Accordion>

  <Accordion title="tenant_id">
    **Purpose:** Track multi-tenant applications

    **Example values:** `"tenant_456"`, `"org_acme"`, `"company_123"`

    Useful for per-tenant analytics and billing.
  </Accordion>
</AccordionGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Use consistent field names">
    Standardize your metadata fields across your application for easier filtering and analysis.

    ```typescript theme={null}
    // Good - consistent naming
    { user_id: "123", feature: "chat" }

    // Bad - inconsistent naming
    { userId: "123", featureName: "chat" }
    ```
  </Accordion>

  <Accordion title="Don't include sensitive data">
    Avoid adding PII, passwords, or other sensitive information to metadata.

    ```typescript theme={null}
    // Good - anonymized
    { user_id: "user_123" }

    // Bad - PII
    { email: "user@example.com", ssn: "123-45-6789" }
    ```
  </Accordion>

  <Accordion title="Keep values simple">
    Use strings and numbers for metadata values. Avoid complex objects.

    ```typescript theme={null}
    // Good - simple values
    { user_id: "123", plan: "pro", count: 5 }

    // Bad - complex object
    { user: { id: 123, profile: { ... } } }
    ```
  </Accordion>

  <Accordion title="Use metadata for filtering">
    Design metadata fields that will be useful for filtering in the dashboard.

    Common filters: user\_id, feature, environment, version, tenant\_id
  </Accordion>
</AccordionGroup>

## Combining with Sessions

You can use both metadata and session tracking together:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    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!" }],
      });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    response = (
        wrapped_client.messages
        .with_session_id("conversation_abc123")
        .with_metadata({
            "user_id": "user_123",
            "feature": "chat",
            "environment": "production",
        })
        .create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            messages=[{"role": "user", "content": "Hello!"}],
        )
    )
    ```
  </Tab>
</Tabs>

## Next Steps

<CardGroup cols={2}>
  <Card title="Session Tracking" icon="users" href="/features/sessions">
    Group related calls with session IDs
  </Card>

  <Card title="Provider SDKs" icon="code" href="/provider-sdks/overview">
    Learn about provider SDK integration
  </Card>

  <Card title="Vercel AI SDK" icon="zap" href="/vercel-ai/overview">
    Learn about Vercel AI SDK integration
  </Card>

  <Card title="Dashboard" icon="gauge" href="https://observ.dev/dashboard">
    View your traces and analytics
  </Card>
</CardGroup>
