Skip to content

Langfuse

The langfuse profile runs Langfuse 4, self-hosted, for LLM traces, sessions, scores and datasets. Traces reach it through the Collector, like every other trace; applications use its API only for what isn't telemetry: scores and datasets, the evaluation data port (ADR-0008).

Its services

Service What it does Published
langfuse-web The UI and the public API. Receives traces from the Collector, and runs the PostgreSQL and ClickHouse migrations on start http://localhost:3300 (LANGFUSE_PORT)
langfuse-worker Processes ingestion and evaluation jobs from the queues No
clickhouse Traces, observations and scores No
redis Valkey, for the Redis protocol: Langfuse's queues and cache in database 0, shared with the gateway (database 1), with the noeviction policy queues need No
minio MinIO, for the S3 port: the langfuse bucket, for events and media http://localhost:9000, and its console on 9001
db-init Creates Langfuse's database, langfuse, on the database adapter, then exits No

The web server and the worker are pinned to the same version and upgraded together. MinIO's image is Chainguard's, which is published as latest only, so it is pinned by digest.

First start

On its first start, Langfuse creates everything from .env, and sign-up is disabled:

  • an organisation and a project, both stackr (LANGFUSE_INIT_ORG_ID, LANGFUSE_INIT_PROJECT_ID)
  • the project's API keys, LANGFUSE_PUBLIC_KEY (pk-lf-...) and LANGFUSE_SECRET_KEY (sk-lf-...), generated by make env
  • an admin user, who signs in at http://localhost:3300 with LANGFUSE_ADMIN_EMAIL (admin@stackr.local) and LANGFUSE_ADMIN_PASSWORD

LANGFUSE_SALT and LANGFUSE_ENCRYPTION_KEY must never change once Langfuse has data: they hash its API keys and encrypt what it stores. make env keeps them as they are.

How traces arrive

Applications and the gateway send traces to the Collector, and the Collector's otlp_http/langfuse exporter sends them on to Langfuse's OTLP endpoint:

otlp_http/langfuse:
  endpoint: http://langfuse-web:3000/api/public/otel
  headers:
    Authorization: Basic ${env:LANGFUSE_OTLP_AUTH}
    x-langfuse-ingestion-version: "4"
  • The credentials are the project's keys as HTTP Basic, LANGFUSE_OTLP_AUTH, which make env derives from LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY on every run, so it always follows them.
  • Only when the profile runs. make up adds this exporter to the traces pipeline only with the langfuse profile, and Langfuse receives traces only when observability runs too.
  • Never directly. Langfuse's own client in an application exports no spans of its own: every trace takes the one route, so none arrives twice (ADR-0011, ADR-0015).

Events-only mode, and the ingestion header

stackr sets none of Langfuse 4's migration settings, so Langfuse runs as a new v4 installation does by default (Langfuse's upgrade guide):

  • Events-only writes (LANGFUSE_MIGRATION_V4_WRITE_MODE=events_only): observations go only to v4's events tables, the observations-first data model, with no legacy traces and observations tables to fill.
  • Direct OpenTelemetry ingestion (LANGFUSE_MIGRATION_V4_NATIVE_OTEL_BEHAVIOUR=direct): spans are written straight into those tables, which assumes the sender has already put the trace's attributes on every span.

The Collector sends the x-langfuse-ingestion-version: 4 header, which selects that v4 ingestion path, so traces are visible in Langfuse as soon as they are written.

Because Langfuse 4 reads a trace's attributes from every span rather than only the root, session.id, user.id, langfuse.trace.name and the tags must be on each span, not only the first. The libraries set them on every span they own, and the application template's Langfuse client sets each turn's and run's session, user and tags.

Scores and datasets

Applications and evaluators reach Langfuse's public API with the project's keys:

Setting On this machine On the stackr network
LANGFUSE_BASE_URL http://localhost:3300 http://langfuse-web:3000
LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY From stackr's .env The same

The libraries' [langfuse] extras and evalr use it for scores (feedback, mirrored as scores on the traces it is about), score configs, datasets and experiments. Media that browsers and SDKs upload goes to MinIO's published port directly.

Checking it

make smoke PROFILES="observability langfuse"

sends a trace with a known id to the Collector's HTTP port, then finds it in Langfuse through the public API (/api/public/v2/observations) and in Tempo, which checks the Collector's route, its credentials and Langfuse's ingestion together. http://localhost:3300/api/public/health answers when Langfuse is up.

Swapping it

Langfuse is an adapter behind two ports. To use Langfuse Cloud or another self-hosted Langfuse, point the Collector's otlp_http/langfuse exporter at it with that project's credentials, and give applications its LANGFUSE_BASE_URL and keys. Nothing in an application changes but its settings.