Multi-Modality - Langfuse

Multi-Modality and Attachments

Langfuse supports multi-modal traces including text, images, audio, and other attachments.

By default, base64 encoded data URIs are handled automatically by the Langfuse SDKs. They are extracted from the payloads commonly used in multi-modal LLMs, uploaded to Langfuse's object storage, and linked to the trace.

This also works if you:

  1. Reference media files via external URLs.
  2. Customize the handling of media files in the SDKs via the LangfuseMedia class.
  3. Integrate via the Langfuse API directly.

Learn more on how to get started and how this works under the hood below.

Examples

ImagesAudioAttachments

Availability

Langfuse Cloud

Multi-modal attachments on Langfuse Cloud are currently free on Langfuse Cloud. We reserve the option to roll out a new pricing metric to account for the additional storage and compute costs associated with large multi-modal traces in the near-term future.

Self-hosting

Multi-modal attachments are available today. You need to configure your own object storage bucket via the Langfuse environment variables (LANGFUSE_S3_MEDIA_UPLOAD_*). See self-hosting documentation for details on these environment variables. S3-compatible APIs are supported across all major cloud providers and can be self-hosted via minio. Note that the configured storage bucket must have a publicly resolvable hostname to support direct uploads via our SDKs and media asset fetching directly from the browser.

Supported media formats

Langfuse supports a wide range of media types, including:

Full list of supported MIME types

Category MIME type File extension
Images image/png .png
Images image/jpeg, image/jpg .jpg, .jpeg
Images image/webp .webp
Images image/gif .gif
Images image/svg+xml .svg
Images image/tiff .tiff
Images image/bmp .bmp
Images image/avif .avif
Images image/heic .heic
Audio audio/mpeg, audio/mp3 .mp3
Audio audio/wav .wav
Audio audio/ogg .ogg
Audio audio/oga .oga
Audio audio/aac .aac
Audio audio/mp4 .m4a
Audio audio/flac .flac
Audio audio/opus .opus
Audio audio/webm .weba
Video video/mp4 .mp4
Video video/webm .webm
Video video/ogg .ogv
Video video/mpeg .mpeg
Video video/quicktime .mov
Video video/x-msvideo .avi
Video video/x-matroska .mkv
Text & code text/plain .txt
Text & code text/html .html
Text & code text/css .css
Text & code text/csv .csv
Text & code text/markdown .md
Text & code text/x-python .py
Text & code application/javascript .js
Text & code text/x-typescript .ts
Text & code application/x-yaml .yaml
Documents application/pdf .pdf
Documents application/msword .doc
Documents application/vnd.openxmlformats-officedocument.wordprocessingml.document .docx
Documents application/vnd.ms-excel .xls
Documents application/vnd.openxmlformats-officedocument.spreadsheetml.sheet .xlsx
Documents application/vnd.openxmlformats-officedocument.presentationml.presentation .pptx
Documents application/rtf .rtf
Data & archives application/json .json
Data & archives application/x-ndjson .jsonl
Data & archives application/xml .xml
Data & archives application/vnd.apache.parquet .parquet
Data & archives application/zip .zip
Data & archives application/gzip .gz
Data & archives application/x-tar .tar
Data & archives application/x-7z-compressed .7z
Data & archives application/octet-stream .bin

If you require support for additional file types, please let us know in our GitHub Discussion where we're actively gathering feedback on multi-modal support.

Get Started

Base64 data URI encoded media

If you use base64 encoded images, audio, or other files in your LLM applications, upgrade to the latest version of the Langfuse SDKs. The Langfuse SDKs automatically detect and handle base64 encoded media by extracting it, uploading it separately as a Langfuse Media file, and including a reference in the trace.

This works with standard Data URI ( MDN) formatted media (like those used by OpenAI and other LLMs).

This notebook includes a couple of examples using the OpenAI SDK and LangChain.

External media (URLs)

Langfuse supports in-line rendering of media files via URLs if they follow common formats. In this case, the media file is not uploaded to Langfuse's object storage but simply rendered in the UI directly from the source.

Supported formats:

Markdown imagesOpenAI content parts


{
  "content": [
    {
      "role": "system",
      "content": "You are an AI trained to describe and interpret images. Describe the main objects and actions in the image."
    },
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "What's happening in this image?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "https://example.com/image.jpg"
          }
        }
      ]
    }
  ]
}

Custom attachments

If you want to have more control or your media is not base64 encoded, you can upload arbitrary media attachments to Langfuse via the SDKs using the new LangfuseMedia class. Wrap media with LangfuseMedia before including it in trace inputs, outputs, metadata, or dataset items. See the multi-modal documentation for examples.

Python SDK

from langfuse import get_client, observe, propagate_attributes
from langfuse.media import LangfuseMedia

# Create a LangfuseMedia object from a file
with open("static/bitcoin.pdf", "rb") as pdf_file:
    pdf_bytes = pdf_file.read()

# Wrap media in LangfuseMedia class
pdf_media = LangfuseMedia(content_bytes=pdf_bytes, content_type="application/pdf")

# Using with the decorator
@observe()
def process_document():
    langfuse = get_client()

# Propagate metadata (including media) to all child observations
    with propagate_attributes(
        metadata={"document": pdf_media}
    ):
        pass

# Or update the current span
    langfuse.update_current_span(
        input={"document": pdf_media}
    )

JavaScript/TypeScript SDK

import fs from "fs";
import { LangfuseMedia } from "@langfuse/core";

// Wrap media in LangfuseMedia class
const wrappedMedia = new LangfuseMedia({
  source: "bytes",
  contentBytes: fs.readFileSync(new URL("./bitcoin.pdf", import.meta.url)),
  contentType: "application/pdf",
});

// Optionally, access media via wrappedMedia.obj
console.log(wrappedMedia.obj);

// Include media in any trace or observation
const span3 = startObservation("media-pdf-generation");

const generation3 = span3.startObservation('llm-call', {
  model: 'gpt-4',
  input: wrappedMedia,
}, {asType: "generation"});

generation3.end();
span3.end();

API

If you use the API directly to log traces to Langfuse, you need to follow these steps:

Upload media to Langfuse

  1. If you use base64 encoded media: you need to extract it from the trace payloads similar to how the Langfuse SDKs do it.
  2. Initialize the upload and get a mediaId and presignedURL: POST /api/public/media.
  3. Upload media file: PUT [presignedURL].

See this end-to-end example (Python) on how to use the API directly to upload media files.

Add reference to mediaId in trace/observation

Use the Langfuse Media Token to reference the mediaId in the trace or observation input, output, or metadata.

How does it work?

When using media files (that are not referenced via external URLs), Langfuse handles them in the following way:

1. Media Upload Process

Detection and Extraction

Security and Optimization

Implementation Details

2. Media Reference System

The base64 data URIs and the wrapped LangfuseMedia objects in Langfuse traces are replaced by references to the mediaId in the following standardized token format, which helps reconstruct the original payload if needed:

@@@langfuseMedia:type={MIME_TYPE}|id={LANGFUSE_MEDIA_ID}|source={SOURCE_TYPE}@@@

Based on this token, the Langfuse UI can automatically detect the mediaId and render the media file inline. The LangfuseMedia class provides utility functions to extract the mediaId from the reference string.

For multi-modal datasets, use Experiments via SDK to fetch dataset items with resolved LangfuseMediaReference objects and pass the media into your model provider.

3. Resolving Media References

When dealing with traces, observations, or dataset items that include media references, you can convert them back to their base64 data URI format using the resolve_media_references utility method provided by the Langfuse client. This is particularly useful for reinserting the original content during fine-tuning, dataset runs, or replaying a generation. The utility method traverses the parsed object and returns a deep copy with all media reference strings replaced by the corresponding base64 data URI representations.

Python SDK

from langfuse import get_client

# Initialize Langfuse client
langfuse = get_client()

# Example object with media references
obj = {
    "image": "@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=bytes@@@",
    "nested": {
        "pdf": "@@@langfuseMedia:type=application/pdf|id=some-other-uuid|source=bytes@@@"
    }
}

# Resolve media references to base64 data URIs
resolved_obj = langfuse.resolve_media_references(
    obj=obj,
    resolve_with="base64_data_uri"
)

# Result:
# {
#     "image": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
#     "nested": {
#         "pdf": "data:application/pdf;base64,JVBERi0xLjcK..."
#     }
# }

JavaScript SDK

import { LangfuseClient } from "@langfuse/client";

const langfuse = new LangfuseClient()

// Example object with media references
const obj = {
  image: "@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=bytes@@@",
  nested: {
    pdf: "@@@langfuseMedia:type=application/pdf|id=some-other-uuid|source=bytes@@@",
  },
};

// Resolve media references to base64 data URIs
const resolvedTrace = await langfuse.resolveMediaReferences({
  obj: obj,
  resolveWith: "base64DataUri",
});

// Result:
// {
//     image: "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
//     nested: {
//         pdf: "data:application/pdf;base64,JVBERi0xLjcK..."
//     }
// }

GitHub Discussions

Enable images in prompt placeholders Disable S3 Media Upload for Base64 Images via Python Client Configuration Support for more modalities and base64 content How can we see traces of MULTIMODAL llms over langfuse ? Add Images in Tracing Supporting OpenAI Vision Langfuse support for Audio prompt input / output Manually creating file names for images saved in Minio Langfuse - not capturing audio tokens information (gpt-4o-audio-preview) LangFuse Low Level SDK does not render images by passing the link

GitHubSupportGitHubIdeas

Upvotes

Discussions last updated: 7/18/2026, 2:42:32 AM (55 hours ago)