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-...) andLANGFUSE_SECRET_KEY(sk-lf-...), generated bymake env - an admin user, who signs in at http://localhost:3300 with
LANGFUSE_ADMIN_EMAIL(admin@stackr.local) andLANGFUSE_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, whichmake envderives fromLANGFUSE_PUBLIC_KEYandLANGFUSE_SECRET_KEYon every run, so it always follows them. - Only when the profile runs.
make upadds this exporter to the traces pipeline only with thelangfuseprofile, and Langfuse receives traces only whenobservabilityruns 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¶
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.