# Langfuse exporter

[Langfuse](https://langfuse.com/) is an open-source observability platform specifically designed for LLM applications. The Langfuse exporter sends your traces to Langfuse, providing detailed insights into model performance, token usage, and conversation flows.

## Installation

**npm**:

```bash
npm install @mastra/langfuse@latest
```

**pnpm**:

```bash
pnpm add @mastra/langfuse@latest
```

**Yarn**:

```bash
yarn add @mastra/langfuse@latest
```

**Bun**:

```bash
bun add @mastra/langfuse@latest
```

## Configuration

### Prerequisites

1. **Langfuse Account**: Sign up at [cloud.langfuse.com](https://cloud.langfuse.com) or deploy self-hosted
2. **API Keys**: Create public/secret key pair in Langfuse Settings → API Keys
3. **Environment Variables**: Set your credentials

```bash
LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxxxxxx
LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxxxxxx
LANGFUSE_BASE_URL=https://cloud.langfuse.com  # Or your self-hosted URL
```

### Zero-Config Setup

With environment variables set, use the exporter with no configuration:

```typescript
import { Mastra } from '@mastra/core'
import { Observability } from '@mastra/observability'
import { LangfuseExporter } from '@mastra/langfuse'

export const mastra = new Mastra({
  observability: new Observability({
    configs: {
      langfuse: {
        serviceName: 'my-service',
        exporters: [new LangfuseExporter()],
      },
    },
  }),
})
```

### Explicit Configuration

You can also pass credentials directly (takes precedence over environment variables):

```typescript
import { Mastra } from '@mastra/core'
import { Observability } from '@mastra/observability'
import { LangfuseExporter } from '@mastra/langfuse'

export const mastra = new Mastra({
  observability: new Observability({
    configs: {
      langfuse: {
        serviceName: 'my-service',
        exporters: [
          new LangfuseExporter({
            publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
            secretKey: process.env.LANGFUSE_SECRET_KEY!,
            baseUrl: process.env.LANGFUSE_BASE_URL,
            environment: process.env.NODE_ENV,
            release: process.env.GIT_COMMIT,
          }),
        ],
      },
    },
  }),
})
```

## Configuration options

### Realtime vs Batch Mode

The Langfuse exporter supports two modes for sending traces:

#### Realtime Mode (Development)

Traces appear immediately in Langfuse dashboard, ideal for debugging:

```typescript
new LangfuseExporter({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  realtime: true, // Flush after each event
})
```

#### Batch Mode (Production)

Better performance with automatic batching:

```typescript
new LangfuseExporter({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  realtime: false, // Default - batch traces
})
```

#### Batch Tuning for High-Volume Traces

For self-hosted Langfuse deployments or streamed runs that produce many spans per second, you can tune the OTEL batch size and flush interval to reduce request pressure on the Langfuse ingestion endpoint:

```typescript
new LangfuseExporter({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  flushAt: 500, // Maximum spans per OTEL export batch
  flushInterval: 20, // Maximum seconds between flushes
})
```

To suppress high-volume span types entirely (for example `MODEL_CHUNK` spans from streamed responses), use the observability-level [`excludeSpanTypes` option](https://mastra.ai/reference/observability/tracing/span-filtering) rather than configuring the exporter:

```typescript
import { SpanType } from '@mastra/core/observability'

new Observability({
  configs: {
    langfuse: {
      serviceName: 'my-service',
      exporters: [new LangfuseExporter()],
      excludeSpanTypes: [SpanType.MODEL_CHUNK],
    },
  },
})
```

### Complete Configuration

```typescript
new LangfuseExporter({
  // Required credentials
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,

  // Optional settings
  baseUrl: process.env.LANGFUSE_BASE_URL, // Default: https://cloud.langfuse.com
  realtime: process.env.NODE_ENV === 'development', // Dynamic mode selection
  flushAt: 500, // Maximum spans per OTEL export batch
  flushInterval: 20, // Maximum seconds between flushes
  logLevel: 'info', // Diagnostic logging: debug | info | warn | error

  // Langfuse-specific settings
  environment: process.env.NODE_ENV, // Shows in Langfuse UI for filtering
  release: process.env.GIT_COMMIT, // Git commit hash for version tracking
})
```

## Scoping evaluators per agent

Langfuse evaluators (such as LLM-as-a-Judge) can be filtered to run only against specific traces. The Mastra Langfuse exporter automatically scopes each trace to the agent or workflow that started it, so trace-level filters resolve to the right runs.

For every trace whose root span is an `AGENT_RUN`, the exporter sets:

- `langfuse.trace.name`: the agent name (or id, when no name is set)
- `langfuse.trace.metadata.agentId`: the agent id
- `langfuse.trace.metadata.agentName`: the agent name

The same applies to `WORKFLOW_RUN` root spans, which set `langfuse.trace.metadata.workflowId` and `langfuse.trace.metadata.workflowName`.

To scope an evaluator to a specific agent, configure either filter in Langfuse:

- **Trace name**: equals the agent name (for example, `weather-agent`).
- **Metadata**: `agentId` equals the agent id.

The trace name dropdown in Langfuse evaluator filters lists every distinct value seen, so each agent appears as its own entry once it has produced at least one trace.

If you set a custom `traceName` via `mastra.metadata.traceName`, your value takes precedence over the default agent name.

## Prompt linking

You can link LLM generations to prompts stored in [Langfuse Prompt Management](https://langfuse.com/docs/prompt-management). This enables version tracking and metrics for your prompts.

### Using the Helper (Recommended)

Use `withLangfusePrompt` with `buildTracingOptions` for the cleanest API:

```typescript
import { Agent } from '@mastra/core/agent'
import { buildTracingOptions } from '@mastra/observability'
import { LangfuseExporter, withLangfusePrompt } from '@mastra/langfuse'

const exporter = new LangfuseExporter()

// Fetch the prompt from Langfuse Prompt Management via the client
const prompt = await exporter.client.prompt.get('customer-support', { type: 'text' })

export const supportAgent = new Agent({
  name: 'support-agent',
  instructions: prompt.compile(), // Use the prompt text from Langfuse
  model: 'openai/gpt-5.5',
  defaultGenerateOptions: {
    tracingOptions: buildTracingOptions(
      withLangfusePrompt({ name: prompt.name, version: prompt.version }),
    ),
  },
})
```

The `withLangfusePrompt` helper accepts `name` and `version` fields for prompt linking. Langfuse v5 requires both fields.

### Manual Fields

You can also pass manual fields if you're not using the Langfuse SDK:

```typescript
const tracingOptions = buildTracingOptions(withLangfusePrompt({ name: 'my-prompt', version: 1 }))
```

### Prompt Object Fields

The prompt object requires both `name` and `version`:

| Field     | Type   | Description                 |
| --------- | ------ | --------------------------- |
| `name`    | string | The prompt name in Langfuse |
| `version` | number | The prompt version number   |

When set on a `MODEL_GENERATION` span, the Langfuse exporter automatically links the generation to the corresponding prompt.

## Related

- [Tracing Overview](https://mastra.ai/docs/observability/tracing/overview)
- [Langfuse Documentation](https://langfuse.com/docs)
- [Langfuse Prompt Management](https://langfuse.com/docs/prompt-management)