0
# Media Management
1
2
The MediaManager provides functionality to resolve media references in Langfuse trace data. Media content (images, audio, video, PDFs, etc.) is stored separately and referenced using special string identifiers. The MediaManager resolves these references back to usable content like base64 data URIs.
3
4
## Capabilities
5
6
### Resolve Media References
7
8
Replace media reference strings in an object with base64 data URIs by fetching the actual media content from Langfuse.
9
10
```typescript { .api }
11
/**
12
* Resolves media reference strings in an object to base64 data URIs
13
*
14
* Recursively traverses the input object looking for media reference strings
15
* in the format "@@@langfuseMedia:...@@@". When found, fetches the actual
16
* media content and replaces the reference with a base64 data URI.
17
*
18
* If fetching fails for a reference, a warning is logged and the reference
19
* string is left unchanged in the output.
20
*
21
* @template T - The type of the object being processed
22
* @param params - Configuration object for resolving references
23
* @returns A deep copy of the input with media references resolved
24
*/
25
async resolveReferences<T>(
26
params: LangfuseMediaResolveMediaReferencesParams<T>
27
): Promise<T>;
28
29
type LangfuseMediaResolveMediaReferencesParams<T> = {
30
/** The object to process for media references */
31
obj: T;
32
/** The format to resolve media references to (currently only "base64DataUri" is supported) */
33
resolveWith: "base64DataUri";
34
/** Maximum depth to traverse when processing nested objects (default: 10) */
35
maxDepth?: number;
36
};
37
```
38
39
**Usage Examples:**
40
41
```typescript
42
import { LangfuseClient } from '@langfuse/client';
43
44
const langfuse = new LangfuseClient();
45
46
// Simple object with media reference
47
const obj = {
48
image: "@@@langfuseMedia:type=image/jpeg|id=abc123|source=bytes@@@",
49
text: "This is a regular string"
50
};
51
52
const resolved = await langfuse.media.resolveReferences({
53
obj,
54
resolveWith: "base64DataUri"
55
});
56
57
// Result:
58
// {
59
// image: "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
60
// text: "This is a regular string"
61
// }
62
```
63
64
**Nested Objects and Arrays:**
65
66
```typescript
67
// Complex nested structure
68
const traceData = {
69
observations: [
70
{
71
input: {
72
message: "Process this image",
73
image: "@@@langfuseMedia:type=image/png|id=img001|source=bytes@@@"
74
},
75
output: {
76
result: "Processed",
77
thumbnail: "@@@langfuseMedia:type=image/jpeg|id=img002|source=bytes@@@"
78
},
79
metadata: {
80
attachments: [
81
"@@@langfuseMedia:type=application/pdf|id=doc001|source=bytes@@@",
82
"@@@langfuseMedia:type=audio/wav|id=aud001|source=bytes@@@"
83
]
84
}
85
}
86
]
87
};
88
89
// Resolves all media references throughout the nested structure
90
const resolved = await langfuse.media.resolveReferences({
91
obj: traceData,
92
resolveWith: "base64DataUri"
93
});
94
95
// All media references are now base64 data URIs
96
console.log(resolved.observations[0].input.image);
97
// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
98
99
console.log(resolved.observations[0].metadata.attachments[0]);
100
// "data:application/pdf;base64,JVBERi0xLjcKJeLjz9MKMSAw..."
101
```
102
103
**Controlling Traversal Depth:**
104
105
```typescript
106
// Deeply nested structure
107
const deepObject = {
108
level1: {
109
level2: {
110
level3: {
111
level4: {
112
level5: {
113
media: "@@@langfuseMedia:type=image/jpeg|id=deep001|source=bytes@@@"
114
}
115
}
116
}
117
}
118
}
119
};
120
121
// Limit traversal depth
122
const resolved = await langfuse.media.resolveReferences({
123
obj: deepObject,
124
resolveWith: "base64DataUri",
125
maxDepth: 3 // Will not process beyond level 3
126
});
127
128
// Media at level 5 will not be resolved due to maxDepth limit
129
```
130
131
**Resolving Trace Data:**
132
133
```typescript
134
// Fetch trace from API (contains media references)
135
const trace = await langfuse.api.trace.get('trace-id-123');
136
137
// Resolve all media references in the trace
138
const resolvedTrace = await langfuse.media.resolveReferences({
139
obj: trace,
140
resolveWith: "base64DataUri"
141
});
142
143
// Now you can use the resolved media content
144
if (resolvedTrace.observations) {
145
for (const obs of resolvedTrace.observations) {
146
if (obs.input?.image) {
147
// image is now a base64 data URI, can be displayed in browser
148
console.log('Image data URI:', obs.input.image);
149
}
150
}
151
}
152
```
153
154
**Error Handling:**
155
156
```typescript
157
// If media fetch fails, the reference string remains unchanged
158
const obj = {
159
validMedia: "@@@langfuseMedia:type=image/jpeg|id=valid123|source=bytes@@@",
160
invalidMedia: "@@@langfuseMedia:type=image/jpeg|id=invalid999|source=bytes@@@"
161
};
162
163
const resolved = await langfuse.media.resolveReferences({
164
obj,
165
resolveWith: "base64DataUri"
166
});
167
168
// Valid media is resolved
169
console.log(resolved.validMedia);
170
// "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
171
172
// Invalid media remains as reference (warning logged)
173
console.log(resolved.invalidMedia);
174
// "@@@langfuseMedia:type=image/jpeg|id=invalid999|source=bytes@@@"
175
```
176
177
### Parse Media Reference String
178
179
Parse a media reference string into its component parts (static method).
180
181
```typescript { .api }
182
/**
183
* Parses a media reference string into a ParsedMediaReference object
184
*
185
* Media reference string format:
186
* "@@@langfuseMedia:type=<mime>|id=<id>|source=<source>@@@"
187
*
188
* @param referenceString - The reference string to parse
189
* @returns Parsed media reference with mediaId, source, and contentType
190
* @throws Error if the reference string is invalid or missing required fields
191
*/
192
static parseReferenceString(
193
referenceString: string
194
): ParsedMediaReference;
195
196
type ParsedMediaReference = {
197
/** The unique identifier for the media content */
198
mediaId: string;
199
/** The source type of the media (e.g., "bytes", "base64_data_uri") */
200
source: string;
201
/** The MIME type of the media content */
202
contentType: MediaContentType;
203
};
204
```
205
206
**Usage Examples:**
207
208
```typescript
209
import { MediaManager } from '@langfuse/client';
210
211
// Parse a valid reference string
212
const referenceString = "@@@langfuseMedia:type=image/jpeg|id=abc-123|source=bytes@@@";
213
214
const parsed = MediaManager.parseReferenceString(referenceString);
215
216
console.log(parsed);
217
// {
218
// mediaId: "abc-123",
219
// source: "bytes",
220
// contentType: "image/jpeg"
221
// }
222
```
223
224
**Extracting Information:**
225
226
```typescript
227
// Use parsed information to understand media type
228
const ref = "@@@langfuseMedia:type=application/pdf|id=doc001|source=base64_data_uri@@@";
229
const parsed = MediaManager.parseReferenceString(ref);
230
231
console.log(`Media ID: ${parsed.mediaId}`); // "doc001"
232
console.log(`Content Type: ${parsed.contentType}`); // "application/pdf"
233
console.log(`Source: ${parsed.source}`); // "base64_data_uri"
234
235
// Determine media category
236
if (parsed.contentType.startsWith('image/')) {
237
console.log('This is an image');
238
} else if (parsed.contentType.startsWith('audio/')) {
239
console.log('This is audio');
240
} else if (parsed.contentType === 'application/pdf') {
241
console.log('This is a PDF document');
242
}
243
```
244
245
**Error Handling:**
246
247
```typescript
248
// Invalid format - missing prefix
249
try {
250
MediaManager.parseReferenceString("type=image/jpeg|id=123|source=bytes@@@");
251
} catch (error) {
252
console.error(error.message);
253
// "Reference string does not start with '@@@langfuseMedia:type='"
254
}
255
256
// Invalid format - missing suffix
257
try {
258
MediaManager.parseReferenceString("@@@langfuseMedia:type=image/jpeg|id=123|source=bytes");
259
} catch (error) {
260
console.error(error.message);
261
// "Reference string does not end with '@@@'"
262
}
263
264
// Invalid format - missing required fields
265
try {
266
MediaManager.parseReferenceString("@@@langfuseMedia:type=image/jpeg|id=123@@@");
267
} catch (error) {
268
console.error(error.message);
269
// "Missing required fields in reference string"
270
}
271
```
272
273
**Finding References in Strings:**
274
275
```typescript
276
// Extract and parse all media references from a string
277
const text = `
278
Image 1: @@@langfuseMedia:type=image/png|id=img1|source=bytes@@@
279
Image 2: @@@langfuseMedia:type=image/jpeg|id=img2|source=bytes@@@
280
PDF: @@@langfuseMedia:type=application/pdf|id=doc1|source=bytes@@@
281
`;
282
283
const regex = /@@@langfuseMedia:.+?@@@/g;
284
const matches = text.match(regex);
285
286
if (matches) {
287
const parsed = matches.map(ref => MediaManager.parseReferenceString(ref));
288
289
console.log('Found media references:');
290
parsed.forEach(p => {
291
console.log(`- ${p.contentType}: ${p.mediaId}`);
292
});
293
// - image/png: img1
294
// - image/jpeg: img2
295
// - application/pdf: doc1
296
}
297
```
298
299
## Reference String Format
300
301
Media reference strings follow a specific format that encodes media metadata:
302
303
```
304
@@@langfuseMedia:type=<mime-type>|id=<media-id>|source=<source-type>@@@
305
```
306
307
**Components:**
308
309
- **Prefix:** `@@@langfuseMedia:`
310
- **type:** MIME type of the media (e.g., `image/jpeg`, `application/pdf`)
311
- **id:** Unique identifier for the media content
312
- **source:** Source type (e.g., `bytes`, `base64_data_uri`)
313
- **Suffix:** `@@@`
314
315
**Examples:**
316
317
```typescript
318
// Image reference
319
"@@@langfuseMedia:type=image/jpeg|id=abc-123-def|source=bytes@@@"
320
321
// PDF reference
322
"@@@langfuseMedia:type=application/pdf|id=doc-456|source=base64_data_uri@@@"
323
324
// Audio reference
325
"@@@langfuseMedia:type=audio/wav|id=sound-789|source=bytes@@@"
326
327
// Video reference
328
"@@@langfuseMedia:type=video/mp4|id=clip-012|source=bytes@@@"
329
```
330
331
## Types
332
333
### MediaContentType
334
335
Union type representing all supported MIME types for media content.
336
337
```typescript { .api }
338
type MediaContentType =
339
// Images
340
| "image/png"
341
| "image/jpeg"
342
| "image/jpg"
343
| "image/webp"
344
| "image/gif"
345
| "image/svg+xml"
346
| "image/tiff"
347
| "image/bmp"
348
// Audio
349
| "audio/mpeg"
350
| "audio/mp3"
351
| "audio/wav"
352
| "audio/ogg"
353
| "audio/oga"
354
| "audio/aac"
355
| "audio/mp4"
356
| "audio/flac"
357
// Video
358
| "video/mp4"
359
| "video/webm"
360
// Text
361
| "text/plain"
362
| "text/html"
363
| "text/css"
364
| "text/csv"
365
// Documents
366
| "application/pdf"
367
| "application/msword"
368
| "application/vnd.ms-excel"
369
// Other
370
| "application/zip"
371
| "application/json"
372
| "application/xml"
373
| "application/octet-stream";
374
375
// Constants for type-safe access
376
const MediaContentType = {
377
// Images
378
ImagePng: "image/png",
379
ImageJpeg: "image/jpeg",
380
ImageJpg: "image/jpg",
381
ImageWebp: "image/webp",
382
ImageGif: "image/gif",
383
ImageSvgXml: "image/svg+xml",
384
ImageTiff: "image/tiff",
385
ImageBmp: "image/bmp",
386
// Audio
387
AudioMpeg: "audio/mpeg",
388
AudioMp3: "audio/mp3",
389
AudioWav: "audio/wav",
390
AudioOgg: "audio/ogg",
391
AudioOga: "audio/oga",
392
AudioAac: "audio/aac",
393
AudioMp4: "audio/mp4",
394
AudioFlac: "audio/flac",
395
// Video
396
VideoMp4: "video/mp4",
397
VideoWebm: "video/webm",
398
// Text
399
TextPlain: "text/plain",
400
TextHtml: "text/html",
401
TextCss: "text/css",
402
TextCsv: "text/csv",
403
// Documents
404
ApplicationPdf: "application/pdf",
405
ApplicationMsword: "application/msword",
406
ApplicationMsExcel: "application/vnd.ms-excel",
407
// Other
408
ApplicationZip: "application/zip",
409
ApplicationJson: "application/json",
410
ApplicationXml: "application/xml",
411
ApplicationOctetStream: "application/octet-stream",
412
} as const;
413
```
414
415
### ParsedMediaReference
416
417
Result type from parsing a media reference string.
418
419
```typescript { .api }
420
type ParsedMediaReference = {
421
/** The unique identifier for the media content */
422
mediaId: string;
423
/** The source type of the media */
424
source: string;
425
/** The MIME type of the media content */
426
contentType: MediaContentType;
427
};
428
```
429
430
### LangfuseMediaResolveMediaReferencesParams
431
432
Parameters for the `resolveReferences` method.
433
434
```typescript { .api }
435
type LangfuseMediaResolveMediaReferencesParams<T> = {
436
/** The object to process for media references */
437
obj: T;
438
/** The format to resolve media references to */
439
resolveWith: "base64DataUri";
440
/** Maximum depth to traverse when processing nested objects (default: 10) */
441
maxDepth?: number;
442
};
443
```
444
445
## Common Use Cases
446
447
### Working with Images
448
449
```typescript
450
import { LangfuseClient } from '@langfuse/client';
451
452
const langfuse = new LangfuseClient();
453
454
// Fetch trace with image references
455
const trace = await langfuse.api.trace.get('trace-123');
456
457
// Resolve image references
458
const resolved = await langfuse.media.resolveReferences({
459
obj: trace,
460
resolveWith: "base64DataUri"
461
});
462
463
// Use resolved images in HTML
464
if (resolved.observations) {
465
for (const obs of resolved.observations) {
466
if (obs.input?.screenshot) {
467
// Create an img element with the data URI
468
const img = document.createElement('img');
469
img.src = obs.input.screenshot; // data:image/png;base64,...
470
document.body.appendChild(img);
471
}
472
}
473
}
474
```
475
476
### Processing PDF Documents
477
478
```typescript
479
// Object with PDF reference
480
const data = {
481
document: "@@@langfuseMedia:type=application/pdf|id=doc123|source=bytes@@@"
482
};
483
484
// Resolve to base64 data URI
485
const resolved = await langfuse.media.resolveReferences({
486
obj: data,
487
resolveWith: "base64DataUri"
488
});
489
490
// Use in iframe or download
491
console.log(resolved.document);
492
// "data:application/pdf;base64,JVBERi0xLjcK..."
493
494
// Display in iframe
495
const iframe = document.createElement('iframe');
496
iframe.src = resolved.document;
497
document.body.appendChild(iframe);
498
```
499
500
### Handling Audio Files
501
502
```typescript
503
// Trace with audio recording reference
504
const trace = {
505
input: {
506
recording: "@@@langfuseMedia:type=audio/wav|id=rec001|source=bytes@@@"
507
}
508
};
509
510
// Resolve audio reference
511
const resolved = await langfuse.media.resolveReferences({
512
obj: trace,
513
resolveWith: "base64DataUri"
514
});
515
516
// Play audio in browser
517
const audio = new Audio(resolved.input.recording);
518
audio.play();
519
520
// Or use in HTML audio element
521
const audioElement = document.createElement('audio');
522
audioElement.src = resolved.input.recording;
523
audioElement.controls = true;
524
document.body.appendChild(audioElement);
525
```
526
527
### Processing Video Content
528
529
```typescript
530
// Video reference in observation
531
const observation = {
532
output: {
533
generatedVideo: "@@@langfuseMedia:type=video/mp4|id=vid001|source=bytes@@@"
534
}
535
};
536
537
// Resolve video
538
const resolved = await langfuse.media.resolveReferences({
539
obj: observation,
540
resolveWith: "base64DataUri"
541
});
542
543
// Display video
544
const video = document.createElement('video');
545
video.src = resolved.output.generatedVideo;
546
video.controls = true;
547
video.width = 640;
548
document.body.appendChild(video);
549
```
550
551
### Batch Processing Multiple Traces
552
553
```typescript
554
// Fetch multiple traces
555
const traces = await langfuse.api.trace.list({ limit: 50 });
556
557
// Resolve all media references across all traces
558
const resolvedTraces = await langfuse.media.resolveReferences({
559
obj: traces,
560
resolveWith: "base64DataUri"
561
});
562
563
// Process each trace with resolved media
564
for (const trace of resolvedTraces.data) {
565
console.log(`Processing trace: ${trace.id}`);
566
567
// Access resolved media content
568
if (trace.observations) {
569
for (const obs of trace.observations) {
570
if (obs.input?.image?.startsWith('data:image/')) {
571
console.log('Found resolved image');
572
}
573
}
574
}
575
}
576
```
577
578
### Selective Media Resolution
579
580
```typescript
581
// Parse references first to decide what to resolve
582
const obj = {
583
largeVideo: "@@@langfuseMedia:type=video/mp4|id=large001|source=bytes@@@",
584
smallImage: "@@@langfuseMedia:type=image/jpeg|id=small001|source=bytes@@@"
585
};
586
587
// Extract reference strings
588
const videoRef = obj.largeVideo;
589
const imageRef = obj.smallImage;
590
591
// Parse to check content type
592
const videoParsed = MediaManager.parseReferenceString(videoRef);
593
const imageParsed = MediaManager.parseReferenceString(imageRef);
594
595
// Only resolve images (skip large videos)
596
const filtered = {
597
smallImage: obj.smallImage,
598
// Exclude largeVideo
599
};
600
601
const resolved = await langfuse.media.resolveReferences({
602
obj: filtered,
603
resolveWith: "base64DataUri"
604
});
605
606
console.log('Resolved only small image, skipped large video');
607
```
608
609
## Best Practices
610
611
### Memory Management
612
613
Be mindful of memory usage when resolving large media files or processing many objects:
614
615
```typescript
616
// Good: Process in batches
617
const traces = await langfuse.api.trace.list({ limit: 10 });
618
const resolved = await langfuse.media.resolveReferences({
619
obj: traces,
620
resolveWith: "base64DataUri"
621
});
622
623
// Less ideal: Processing too many large files at once
624
// const manyTraces = await langfuse.api.trace.list({ limit: 1000 });
625
// May cause memory issues if traces contain large media
626
```
627
628
### Error Resilience
629
630
The `resolveReferences` method handles individual fetch failures gracefully:
631
632
```typescript
633
// Some references may fail to fetch, but the method continues
634
const obj = {
635
validImage: "@@@langfuseMedia:type=image/jpeg|id=valid|source=bytes@@@",
636
missingImage: "@@@langfuseMedia:type=image/jpeg|id=deleted|source=bytes@@@",
637
anotherValidImage: "@@@langfuseMedia:type=image/png|id=valid2|source=bytes@@@"
638
};
639
640
const resolved = await langfuse.media.resolveReferences({
641
obj,
642
resolveWith: "base64DataUri"
643
});
644
645
// Valid images are resolved, invalid ones remain as references
646
// Warnings are logged for failed fetches
647
```
648
649
### Caching Results
650
651
Consider caching resolved media to avoid repeated fetches:
652
653
```typescript
654
const cache = new Map<string, string>();
655
656
async function getResolvedMedia(referenceString: string): Promise<string> {
657
if (cache.has(referenceString)) {
658
return cache.get(referenceString)!;
659
}
660
661
const resolved = await langfuse.media.resolveReferences({
662
obj: { media: referenceString },
663
resolveWith: "base64DataUri"
664
});
665
666
cache.set(referenceString, resolved.media);
667
return resolved.media;
668
}
669
670
// Use cached resolver
671
const image1 = await getResolvedMedia(
672
"@@@langfuseMedia:type=image/jpeg|id=abc|source=bytes@@@"
673
);
674
const image2 = await getResolvedMedia(
675
"@@@langfuseMedia:type=image/jpeg|id=abc|source=bytes@@@" // Cache hit
676
);
677
```
678
679
### Type Safety
680
681
Use TypeScript generics to maintain type information:
682
683
```typescript
684
interface TraceWithMedia {
685
id: string;
686
observations: Array<{
687
input?: {
688
image?: string;
689
};
690
}>;
691
}
692
693
// Type is preserved through resolution
694
const trace: TraceWithMedia = await langfuse.api.trace.get('trace-123');
695
const resolved: TraceWithMedia = await langfuse.media.resolveReferences({
696
obj: trace,
697
resolveWith: "base64DataUri"
698
});
699
700
// TypeScript knows the structure
701
console.log(resolved.observations[0].input?.image);
702
```
703
704
### Controlling Recursion
705
706
Use `maxDepth` to prevent excessive recursion on deeply nested structures:
707
708
```typescript
709
// Limit traversal for performance
710
const resolved = await langfuse.media.resolveReferences({
711
obj: veryNestedObject,
712
resolveWith: "base64DataUri",
713
maxDepth: 5 // Don't traverse deeper than 5 levels
714
});
715
```
716
717
## Integration Patterns
718
719
### With Web Applications
720
721
```typescript
722
// React example
723
import { LangfuseClient } from '@langfuse/client';
724
import { useState, useEffect } from 'react';
725
726
function TraceViewer({ traceId }: { traceId: string }) {
727
const [resolvedTrace, setResolvedTrace] = useState(null);
728
const langfuse = new LangfuseClient();
729
730
useEffect(() => {
731
async function loadTrace() {
732
const trace = await langfuse.api.trace.get(traceId);
733
const resolved = await langfuse.media.resolveReferences({
734
obj: trace,
735
resolveWith: "base64DataUri"
736
});
737
setResolvedTrace(resolved);
738
}
739
loadTrace();
740
}, [traceId]);
741
742
if (!resolvedTrace) return <div>Loading...</div>;
743
744
return (
745
<div>
746
{resolvedTrace.observations?.map((obs, idx) => (
747
<div key={idx}>
748
{obs.input?.image && (
749
<img src={obs.input.image} alt="Trace input" />
750
)}
751
</div>
752
))}
753
</div>
754
);
755
}
756
```
757
758
### With Server-Side Processing
759
760
```typescript
761
// Node.js server example
762
import { LangfuseClient } from '@langfuse/client';
763
import express from 'express';
764
765
const app = express();
766
const langfuse = new LangfuseClient();
767
768
app.get('/api/trace/:traceId', async (req, res) => {
769
try {
770
const trace = await langfuse.api.trace.get(req.params.traceId);
771
772
// Resolve media references before sending to client
773
const resolved = await langfuse.media.resolveReferences({
774
obj: trace,
775
resolveWith: "base64DataUri"
776
});
777
778
res.json(resolved);
779
} catch (error) {
780
res.status(500).json({ error: error.message });
781
}
782
});
783
784
app.listen(3000);
785
```
786
787
### With Data Processing Pipelines
788
789
```typescript
790
// ETL pipeline example
791
import { LangfuseClient } from '@langfuse/client';
792
793
const langfuse = new LangfuseClient();
794
795
async function exportTracesWithMedia() {
796
const traces = await langfuse.api.trace.list({ limit: 100 });
797
798
// Resolve all media in batch
799
const resolved = await langfuse.media.resolveReferences({
800
obj: traces,
801
resolveWith: "base64DataUri"
802
});
803
804
// Export to file or database with resolved media
805
for (const trace of resolved.data) {
806
await saveToDatabase(trace); // Media is now embedded as base64
807
}
808
}
809
```
810