Export to blob storage
- HobbyNot Available
- CoreNot Available
- ProTeams Add-on required
- EnterpriseAvailable
- Self HostedAvailable
Overview
Schedule exports to Amazon S3, S3-compatible storage, Google Cloud Storage, or Azure Blob Storage every 20 minutes, hourly, daily, or weekly.
Configure the export
Create the integration
- Open Project Settings > Integrations > Blob Storage.
- Select your provider and enter its bucket, path, and credentials. Self-hosters can find per-vendor bucket and credential setup on the blob storage deployment page.
- Choose the file format, schedule, export mode, and field groups.
- Enable the integration and save. The first run starts shortly afterward.
![]()
| Setting | Choices and behavior |
|---|---|
| Provider and access | AWS S3, S3 Compatible Storage, or Azure Blob Storage. Google Cloud Storage is reached through S3 Compatible Storage: set the endpoint to https://storage.googleapis.com and authenticate with an HMAC key pair rather than a service account. |
| Format | Parquet (default), CSV, JSON, or JSONL. Text formats can be gzip-compressed; Parquet uses its own encoding and compression. |
| Schedule | Every 20 minutes, hourly, daily, or weekly. Each run exports one time window. |
| Export Mode | Full history starts at the project's earliest data; From setup date starts when the integration is enabled; From custom date starts at a selected date. Changing this setting resets the sync position and re-scans from that point. |
The integration settings page shows a status badge:
| Badge | Meaning |
|---|---|
| Active | Enabled and synced; the next run is scheduled. |
| Running | A run is in progress. |
| Queued | A run is due and waiting. |
| Pending | Enabled but has not run yet. |
| Disabled | Turned off. |
| Error | The last run failed; the message and timestamp are shown. |
Parquet notes
- Observation files omit
input_price,output_price, andtotal_price. Usecost_detailsandtotal_cost; trace and score fields are unaffected. - On self-hosted ClickHouse older than 25.11, upgrade ClickHouse or use CSV, JSON, or JSONL because incomplete Parquet output may not be reported.
Use Validate before saving to check that Langfuse can access the target with the supplied credentials. The integration then writes all output beneath the configured prefix without changing other objects in the bucket.
Langfuse writes exports to your bucket using this structure:
{prefix}{project-id}/
โโโ observations_v2/
โ โโโ {timestamp}.{parquet|json|jsonl|csv}[.gz]
โโโ scores/
โ โโโ {timestamp}.{parquet|json|jsonl|csv}[.gz]
โโโ manifests/
โโโ {timestamp}.jsonField selection
Observation columns are configurable; score columns are fixed.
New integrations select all eleven field groups. core is required; disable other groups to reduce file size or omit sensitive data.
| Group | Fields |
|---|---|
core | end_time, id, parent_observation_id, project_id, start_time, trace_id, type |
basic | bookmarked, environment, is_root_observation, level, name, public, session_id, status_message, user_id, version |
time | completion_start_time, created_at, updated_at |
io | input, output |
metadata | metadata |
model | input_price, model_id, model_parameters, output_price, provided_model_name, total_price |
usage | cost_details, total_cost, usage_details, usage_pricing_tier_id, usage_pricing_tier_name |
prompt | prompt_id, prompt_name, prompt_version |
metrics | latency, time_to_first_token |
trace_context | release, tags, trace_name |
tools | tool_call_names, tool_calls, tool_definitions |
Changes apply only to future exports. See the observation field reference for types and descriptions.
Scores are always exported and their fields cannot be selected.
| Category | Fields |
|---|---|
| Identity | id, project_id, timestamp, created_at, updated_at |
| Context and links | trace_id, observation_id, session_id, dataset_run_id, environment |
| Score | name, data_type, value, string_value, source, comment |
See the score field reference for types and descriptions.
Configure through the API
Use the public endpoint to read or update the integration:
GET /api/public/integrations/blob-storage
PUT /api/public/integrations/blob-storageOn PUT, exportFieldGroups must include core; omit the property to keep the current selection. compressed applies only to CSV, JSON, and JSONL.
See the REST API reference for authentication, provider settings, and the complete schema.
Process exports
Use each run's manifest as the unit of work.
Know when an export is complete
A run is complete only when its manifest exists at {prefix}{project-id}/manifests/{timestamp}.json. Langfuse writes it after every data file uploads successfully.
If an upload fails, no manifest is written. The run is retried and any data objects under the same keys are overwritten.
When a manifest appears:
- Read
files[]. - Fetch every full object key in
files[].key. Do not derive filenames or list table directories. - Deduplicate records by ID because adjacent export windows share an inclusive boundary.
| Field | Purpose |
|---|---|
window | Inclusive minTimestamp and maxTimestamp for the run |
exportSource, tables | Export source and tables included |
files[] | Object key, table, format, compression, uploaded size, and row count for each data file |
For Parquet, files[].rowCount is null; inspect the file metadata when you need a count. Ignore unknown manifest fields so additive changes do not break your parser.
Trigger your pipeline
Subscribe to object-created events filtered to {prefix}{project-id}/manifests/, then fetch the manifest and process each files[].key.
- Amazon S3: S3 Event Notifications or EventBridge
- Google Cloud Storage: Pub/Sub notifications for
OBJECT_FINALIZE - Azure Blob Storage: Event Grid for
Microsoft.Storage.BlobCreated - MinIO: bucket notifications
- Backblaze B2: event notifications
If your S3-compatible provider has no object-created events, poll the manifest prefix and checkpoint the latest processed key. Manifest names sort by export timestamp.
Make manifest processing idempotent. Provider events can be delivered more than once, and a catch-up can create several manifests close together.
Upgrade a legacy export
Complete this upgrade if your integration uses Traces and observations
(legacy) or your bucket receives traces/ and observations/ files. On
Langfuse Cloud, remaining legacy exports switch on November 16, 2026 (2026-11-16). On self-hosted v4, the legacy source stops
producing data after the server switches to events_only.
What changes in the exported data
The legacy source writes observation data to observations/ and trace context to a separate traces/ file, which consumers join on trace_id. The enriched source writes a single observations_v2/ file in which each observation row already carries its trace context.
Field groups select columns in both observation files. Three groups contain fewer fields in the legacy observations/ file; the rest are identical:
| Group | observations_v2/ | observations/ |
|---|---|---|
basic | bookmarked, environment, is_root_observation, level, name, public, session_id, status_message, user_id, version | environment, level, name, status_message, version |
usage | cost_details, total_cost, usage_details, usage_pricing_tier_id, usage_pricing_tier_name | Same, without usage_pricing_tier_id |
trace_context | release, tags, trace_name | No effect; these fields are in the traces/ file (name for trace_name) |
The traces/ file itself has a fixed schema that field groups do not apply to. Its trace-level input, output, metadata, timestamp, and version have no direct equivalent in observations_v2/, where identically named fields hold observation-level data.
For every column in each file, see the legacy field reference.
Switch to enriched observations
Most integrations can switch directly once their consumer supports the enriched layout:
On self-hosted Langfuse v4, first switch the server to dual write mode and complete the historic data migration.
Enriched export sources require the deployment to write the v4 events table, so they are unavailable only in legacy write mode. Legacy export sources are unavailable in events_only, which is the default. Switch the integration before the server's events_only cutover.
- Prepare the new consumer. Process
observations_v2/andscores/from each manifest'sfiles[].key. Use the enriched field reference. - Switch the export. Select Enriched observations (recommended).
- Verify and retire legacy. Process the next completed export with the new consumer. After it succeeds, retire the consumer that reads
traces/andobservations/.
Optional: keep both layouts during the cutover.
If your pipeline cannot tolerate a cutover gap, temporarily select Traces and observations (legacy) and enriched observations after step 1.
This writes observations/ and observations_v2/ for subsequent windows only; it does not backfill earlier exports. Run both consumers until the new one is validated, then continue with step 2.
Do not load both observation layouts into the same production dataset. Check the export compatibility matrix if this option is unavailable.
Cutover checks
- All deployments:
traces/andobservations/stop receiving files after the switch, including empty files. Usemanifests/as the run-completion signal. - Langfuse Cloud: Ignore
DEPRECATION_NOTICE.txtwhen processing exports; it is not part of a run. - Self-hosted Langfuse v4:
dualis the only write mode in which both layouts are selectable, so the optional dual-layout validation above requires it.
Export field reference
Field names and types for each exported file. Types match JSON and JSONL output. Timestamps use YYYY-MM-DD HH:MM:SS.ffffff in UTC. Each schema is collapsed on its own belowโopen the file you need.
| File | When it is exported | Schema |
|---|---|---|
observations_v2/ | Current enriched export | Enriched observations |
scores/ | Every export | Scores |
traces/ | Deprecated legacy export | Legacy exports |
observations/ | Deprecated legacy export | Legacy exports |
Enriched observations โ observations_v2/
Each row represents one observation and includes its trace context. Only the selected field groups appear; core is always included.
| Field | Type | Description |
|---|---|---|
id | string | Unique observation identifier. |
trace_id | string | Trace identifier shared by related observations and scores. |
project_id | string | Langfuse project identifier. |
environment | string | Environment label. |
type | string | Observation type: SPAN, GENERATION, EVENT, AGENT, TOOL, CHAIN, RETRIEVER, EVALUATOR, EMBEDDING, or GUARDRAIL. |
parent_observation_id | string | Parent observation identifier; empty for a root observation. |
is_root_observation | boolean | Whether the observation is a logical root. |
start_time | string (timestamp) | When the observation started. |
end_time | string (timestamp) or null | When the observation ended. |
name | string | User-defined observation name. |
metadata | object | User-supplied observation metadata. |
level | string | DEBUG, DEFAULT, WARNING, or ERROR. |
status_message | string | Status or error message. |
version | string | User-defined version. |
input | string | Observation input; may contain plain text or JSON. |
output | string | Observation output; may contain plain text or JSON. |
provided_model_name | string | Model name supplied by the SDK or user. |
model_parameters | string | Model parameters encoded as JSON. |
usage_details | object (string โ integer) | Token usage by category, such as input, output, and total. |
cost_details | object (string โ number) | Cost in USD by category. |
completion_start_time | string (timestamp) or null | When the first streamed token was generated. |
prompt_name | string | Langfuse prompt name. |
prompt_version | integer or null | Langfuse prompt version. |
total_cost | number | Total observation cost in USD; 0 when no cost was recorded. |
latency | number or null | Duration in seconds. |
time_to_first_token | number or null | Time to first token in seconds. |
model_id | string | Matched Langfuse model definition identifier. |
created_at | string (timestamp) | Row creation time. |
updated_at | string (timestamp) | Last row update time. |
prompt_id | string | Langfuse prompt identifier. |
tool_calls | array of strings | Tool calls encoded as JSON strings. |
tool_call_names | array of strings | Names of called tools. |
tool_definitions | object | Tool or function schemas supplied to the model. |
usage_pricing_tier_id | string or null | Pricing tier identifier used for cost calculation. |
usage_pricing_tier_name | string or null | Pricing tier name used for cost calculation. |
input_price | string or null | Matched per-unit input price; omitted from Parquet. |
output_price | string or null | Matched per-unit output price; omitted from Parquet. |
total_price | string or null | Matched flat per-call price; omitted from Parquet. |
user_id | string | End-user identifier from the trace. |
session_id | string | Session identifier from the trace. |
trace_name | string | Trace name. |
tags | array of strings | Trace tags. |
release | string | Trace release. |
bookmarked | boolean | Whether the trace is bookmarked. |
public | boolean | Whether the trace is public. |
Integrations created on or after 2026-04-01 export latency and
time_to_first_token in seconds. Older integrations export these fields in
milliseconds for backward compatibility.
Scores โ scores/
Scores are always exported. Their fields are not configurable. Scores with data type NUMERIC, BOOLEAN, CATEGORICAL, or TEXT are included; corrections (data type CORRECTION) are not.
| Field | Type | Description |
|---|---|---|
id | string | Unique score identifier. |
timestamp | string (timestamp) | Score creation time. |
project_id | string | Langfuse project identifier. |
environment | string | Environment label. |
trace_id | string or null | Associated trace identifier. |
observation_id | string or null | Associated observation identifier. |
session_id | string or null | Associated session identifier. |
dataset_run_id | string or null | Associated dataset run identifier. |
name | string | Score name. |
value | number | Numeric value; TEXT scores use 0. |
source | string | API, ANNOTATION, or EVAL. |
comment | string or null | Optional comment or evaluator reasoning. |
data_type | string | NUMERIC, BOOLEAN, CATEGORICAL, or TEXT. |
string_value | string or null | Category label or text value; null for numeric scores. |
created_at | string (timestamp) | Row creation time. |
updated_at | string (timestamp) | Last row update time. |
Legacy exports โ traces/ and observations/
Legacy exports are deprecated. They split trace context into traces/ and observation data into observations/; consumers join them on trace_id. See upgrade a legacy export before changing a consumer.
Traces (traces/)
The trace file has a fixed schema; field groups do not apply.
| Field | Type | Description |
|---|---|---|
id | string | Unique trace identifier. |
timestamp | string (timestamp) | Trace creation time. |
name | string | User-defined trace name. |
environment | string | Environment label. |
project_id | string | Langfuse project identifier. |
metadata | object | Trace metadata. |
user_id | string or null | End-user identifier. |
session_id | string or null | Session identifier. |
release | string or null | Application release. |
version | string or null | User-defined version. |
public | boolean | Whether the trace is public. |
bookmarked | boolean | Whether the trace is bookmarked. |
tags | array of strings | Trace tags. |
input | string or null | Trace input. |
output | string or null | Trace output. |
created_at | string (timestamp) | Row creation time. |
updated_at | string (timestamp) | Last row update time. |
Legacy trace-level input, output, metadata, timestamp, and version do not have direct equivalents in observations_v2/. Observation fields with the same names contain observation-level data instead.
The trace file does not include total_cost, latency, observations, scores, or html_path.
Observations (observations/)
Each row represents one observation without its trace context; join trace_id to the traces/ file to add it. Only the selected field groups appear; core is always included.
| Field | Type | Description |
|---|---|---|
id | string | Unique observation identifier. |
trace_id | string | Trace identifier shared by related observations and scores. |
project_id | string | Langfuse project identifier. |
environment | string | Environment label. |
type | string | Observation type: SPAN, GENERATION, EVENT, AGENT, TOOL, CHAIN, RETRIEVER, EVALUATOR, EMBEDDING, or GUARDRAIL. |
parent_observation_id | string or null | Parent observation identifier; null for a root observation. |
start_time | string (timestamp) | When the observation started. |
end_time | string (timestamp) or null | When the observation ended. |
name | string | User-defined observation name. |
metadata | object | User-supplied observation metadata. |
level | string | DEBUG, DEFAULT, WARNING, or ERROR. |
status_message | string or null | Status or error message. |
version | string or null | User-defined version. |
input | string or null | Observation input; may contain plain text or JSON. |
output | string or null | Observation output; may contain plain text or JSON. |
provided_model_name | string or null | Model name supplied by the SDK or user. |
model_parameters | string or null | Model parameters encoded as JSON. |
usage_details | object (string โ integer) | Token usage by category, such as input, output, and total. |
cost_details | object (string โ number) | Cost in USD by category. |
completion_start_time | string (timestamp) or null | When the first streamed token was generated. |
prompt_name | string or null | Langfuse prompt name. |
prompt_version | integer or null | Langfuse prompt version. |
total_cost | number or null | Total observation cost in USD. |
latency | number or null | Duration in seconds. |
time_to_first_token | number or null | Time to first token in seconds. |
model_id | string or null | Matched Langfuse model definition identifier. |
created_at | string (timestamp) | Row creation time. |
updated_at | string (timestamp) | Last row update time. |
prompt_id | string or null | Langfuse prompt identifier. |
tool_calls | array of strings | Tool calls encoded as JSON strings. |
tool_call_names | array of strings | Names of called tools. |
tool_definitions | object | Tool or function schemas supplied to the model. |
usage_pricing_tier_name | string or null | Pricing tier name used for cost calculation. |
input_price | string or null | Matched per-unit input price; omitted from Parquet. |
output_price | string or null | Matched per-unit output price; omitted from Parquet. |
total_price | string or null | Matched flat per-call price; omitted from Parquet. |
Where a field appears in both observation files it carries the same meaning. Unset values are encoded differently, though: a field that is null above maps to one of three values in observations_v2/ JSON and JSONL output.
Value in observations_v2/ | Fields |
|---|---|
"" (empty string) | input, model_id, model_parameters, output, parent_observation_id, prompt_id, prompt_name, provided_model_name, status_message, version |
null | completion_start_time, end_time, input_price, latency, output_price, prompt_version, time_to_first_token, total_price, usage_pricing_tier_name |
0 | total_cost |
Empty strings appear where the v4 events table stores the column as non-nullable. total_cost reads from cost_details['total'], so a 0 there cannot be told apart from a genuine zero cost.
For the field groups that select these columns and how they differ from the enriched export, see what changes in the exported data.
Parquet differences
Parquet uses internal encoding and compression, so gzip does not apply.
Observation files omit input_price, output_price, and total_price. Use cost_details and total_cost for cost data.
Trace and score fields are the same across all formats.
For paths, filenames, and the manifest workflow, see process exports.
FAQ
- How do blob storage export timing and retries work?
- I changed my blob storage config โ why didn't it re-export, and why do I still see an error?
- Why do I see empty files in my blob storage export?
Last updated on