AI · Convex component
convex-langfuse
Send LLM traces, generations, and scores from your Convex app to Langfuse over OpenTelemetry, with reactive local queries.
npm install convex-langfuse20downloads last week
669downloads last 12 months
v0.0.5latest, Sep 18, 2026
5releases since Sep 12, 2026
Downloads
Download history
Loading download history…
Build this
Build with convex-langfuse
The install and setup steps from the package documentation.
- 1
Install
bashnpm install convex-langfuseRequirements: Convex v1.33.1 or later, Node.js 18+, a project (Cloud or self-hosted, OTel-compatible)
- 2
Quick Start
Three steps to send traces from your Convex app to Langfuse.
1. Add the component
In
convex/convex.config.ts:tsimport { defineApp } from "convex/server"; import convexLangfuse from "convex-langfuse/convex.config"; const app = defineApp(); app.use(convexLangfuse); export default app;2. Set environment variables
bashnpx convex env set LANGFUSE_PUBLIC_KEY pk-lf-xxxxxxxxxxxx npx convex env set LANGFUSE_SECRET_KEY sk-lf-xxxxxxxxxxxx3. Initialize the client
In
convex/observability.ts:tsimport { components } from "./_generated/api"; import { Langfuse } from "convex-langfuse"; export const langfuse = new Langfuse(components.convexLangfuse, { publicKey: process.env.LANGFUSE_PUBLIC_KEY!, secretKey: process.env.LANGFUSE_SECRET_KEY!, // baseUrl defaults to the EU Langfuse Cloud region — set it for US/JP/self-hosted });Import
langfusefrom this file in any Convex action that calls an LLM. - 3
Usage
Log a generation
tsexport const chat = action({ args: { userId: v.string(), prompt: v.string() }, handler: async (ctx, args) => { const completion = await callYourModel(args.prompt); const { traceId } = await langfuse.logGeneration(ctx, { name: "chat-completion", userId: args.userId, model: "gpt-5", input: args.prompt, output: completion, inputTokens: completion.usage.inputTokens, outputTokens: completion.usage.outputTokens, }); return { completion, traceId }; }, }); // Returns: { traceId, observationId }Log a non-LLM step
tsawait langfuse.logSpan(ctx, { traceId, name: "vector-search", input: { query }, output: { matches }, });Record a score
tsexport const rate = action({ args: { traceId: v.string(), value: v.number() }, handler: async (ctx, args) => { await langfuse.recordScore(ctx, { traceId: args.traceId, name: "user-rating", value: args.value, // e.g. 1 for thumbs up, 0 for thumbs down }); return null; }, });Read a trace reactively
tsexport const getTrace = query({ args: { traceId: v.string() }, handler: async (ctx, args) => langfuse.getTrace(ctx, args), }); export const getObservations = query({ args: { traceId: v.string() }, handler: async (ctx, args) => langfuse.listObservations(ctx, args), });