Import from Langfuse
Do the shared setup first: an ingest
key, pip install metergraphrelay, and a .env holding
METERGRAPH_APP_TOKEN.
What the relay reads
Section titled “What the relay reads”Langfuse GENERATION observations, which are the records of individual
model calls, through the v2 Observations API
(GET /api/public/v2/observations). Langfuse Cloud and self-hosted Langfuse
v4 or newer both work. SPAN and EVENT observations, scores and evals are
never read.
What you need
Section titled “What you need”| Credentials | A Langfuse project’s public and secret key |
| Langfuse version | Cloud, or self-hosted v4 and newer |
| Host | Langfuse Cloud US by default. Set LANGFUSE_BASE_URL for the EU region or your own instance |
Add the keys to the .env you created during the shared setup.
METERGRAPH_APP_TOKEN=<your ingest key>LANGFUSE_PUBLIC_KEY=pk-lf-...LANGFUSE_SECRET_KEY=sk-lf-...# LANGFUSE_BASE_URL=https://cloud.langfuse.com # EU region, or your own hostBoth keys can also be passed as --langfuse-public-key and
--langfuse-secret-key, but the .env route keeps them off the process
list.
Backfill
Section titled “Backfill”-
Decide what to import
Section titled “Decide what to import”Langfuse’s trace name is the closest thing it has to a workflow name, and tags are the usual way a project separates environments. Work out which names and tags identify the traffic you want, and how far back to go.
-
Pull it to a file
Section titled “Pull it to a file”metergraphrelay pull langfuse --trace-name support-bot --tag prod \--since 2026-08-01T00:00:00Z --until 2026-08-08T00:00:00Z \--output langfuse.jsonlSelector Meaning --trace-nameThe Langfuse trace name. Repeatable, and any of the names matches --tagA trace tag. Repeatable, and all of the tags must be present --environmentA single Langfuse environment value --since/--untilBound the observation’s start time. --sinceis inclusive,--untilis exclusive and defaults to the moment the command started-n,--countCaps observations, never traces. Defaults to 100 --routeOverrides the route on every row. Not a selector With no selectors at all you get the latest 100 GENERATION observations in the project.
-
Read the file, then upload it
Section titled “Read the file, then upload it”head -n 2 langfuse.jsonlmetergraphrelay push langfuse.jsonl -
Check the first rows
Section titled “Check the first rows”Open Traces in Metergraph. The route should read as your Langfuse trace name. If every row shows something else, pass
--routeand pull again.
Keep it current
Section titled “Keep it current”metergraphrelay sync langfuse --source-scope support-bot-prod \ --initial-since 2026-08-01T00:00:00Z --trace-name support-bot --tag prodSync takes no --since, --until or -n: the server picks the window. It
takes the same --trace-name, --tag and --environment selectors as
pull, plus --source-scope, --initial-since, --max-window-seconds,
--route and --allow-skipped.
Give each selector set its own --source-scope, and never change one once it
has run. The full contract, including windows, overlap, leases and exit
codes, is on How ongoing sync works.
What lands in Metergraph
Section titled “What lands in Metergraph”| Field | Where it comes from |
|---|---|
| Route | The Langfuse trace name. If the trace has none, the generation’s own name. --route overrides both |
| Timestamp | The observation’s startTime |
| Provider and model | Inferred from the observation’s model field |
| Input tokens | The named input total plus every other input bucket Langfuse reported, so it is the whole prompt |
| Output tokens | The same rollup on the output side |
| Cache reads, cache writes, reasoning | Langfuse’s own buckets, wherever the integration recorded them |
| Cost | Langfuse’s totalCost |
| Status | error when the observation’s level is ERROR, otherwise success |
| Error type | The observation’s statusMessage |
| Content | Input and output, copied verbatim |
| Trace, span and parent span | The Langfuse trace id, observation id and parent observation id |
| Session | The observation’s sessionId |
| Environment | The observation’s environment |
| Tags | Langfuse trace tags, under langfuse_tags |
What does not carry over
Section titled “What does not carry over”- Latency. The relay reads the observation’s start time only, so an
imported Langfuse row has no
latency_ms. This is the one supported source where that is true. - Tool calls and tool names.
- Function attribution, streaming detail, outcomes and repository identity, as on every import path.
- Spans, events, scores and evals, which are never read.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | What to do |
|---|---|---|
| A self-hosted Langfuse rejects the request | Langfuse older than v4 | Upgrade. The relay needs the v2 Observations API |
| Cache or reasoning columns are empty | The integration never recorded those buckets | Nothing to fix. The totals are still right |
| Every route is the generation name rather than a workflow | The traces carry no name | Pass --route |
| A pull returns 0 rows just after a run | Langfuse Cloud has not made the observations readable yet | Wait, then rerun |