0
# Trace ID Generation
1
2
The `createTraceId()` function provides utilities for generating OpenTelemetry-compatible trace IDs with support for both deterministic (seeded) and random generation. This is particularly useful for correlating external IDs with Langfuse traces.
3
4
## Core Function
5
6
### createTraceId
7
8
Creates a trace ID for OpenTelemetry spans with optional deterministic generation.
9
10
```typescript { .api }
11
/**
12
* Creates a trace ID for OpenTelemetry spans.
13
*
14
* @param seed - A seed string for deterministic trace ID generation.
15
* If provided (non-empty), the same seed will always generate the same trace ID.
16
* If empty or falsy, generates a random trace ID.
17
*
18
* Using a seed is especially useful when trying to correlate external,
19
* non-W3C compliant IDs with Langfuse trace IDs. This allows you to later
20
* have a method available for scoring the Langfuse trace given only the
21
* external ID by regenerating the same trace ID from the external ID.
22
*
23
* @returns A Promise that resolves to a 32-character lowercase hexadecimal string
24
* suitable for use as an OpenTelemetry trace ID.
25
*/
26
async function createTraceId(seed?: string): Promise<string>;
27
```
28
29
## Output Format
30
31
The function returns a 32-character lowercase hexadecimal string that conforms to the OpenTelemetry trace ID format:
32
33
```typescript
34
// Example outputs
35
"a1b2c3d4e5f67890a1b2c3d4e5f67890" // Random
36
"f8e7d6c5b4a3928170f8e7d6c5b4a392" // From seed "my-session-123"
37
"c4b3a29180f7e6d5c4b3a29180f7e6d5" // From seed "user-456"
38
```
39
40
## Random Trace IDs
41
42
Generate unique, random trace IDs for each operation.
43
44
```typescript
45
import { createTraceId } from '@langfuse/tracing';
46
47
// Generate random trace IDs
48
const traceId1 = await createTraceId();
49
const traceId2 = await createTraceId();
50
51
console.log(traceId1); // "a1b2c3d4e5f67890a1b2c3d4e5f67890"
52
console.log(traceId2); // "f8e7d6c5b4a3928170f8e7d6c5b4a392"
53
console.log(traceId1 === traceId2); // false - different IDs
54
55
// Alternative: empty string also generates random ID
56
const randomId = await createTraceId("");
57
```
58
59
## Deterministic Trace IDs
60
61
Generate consistent trace IDs from a seed string for correlation purposes.
62
63
```typescript
64
import { createTraceId } from '@langfuse/tracing';
65
66
// Same seed always produces the same trace ID
67
const traceId1 = await createTraceId("my-session-123");
68
const traceId2 = await createTraceId("my-session-123");
69
70
console.log(traceId1 === traceId2); // true - identical IDs
71
72
// Different seeds produce different IDs
73
const sessionA = await createTraceId("session-a");
74
const sessionB = await createTraceId("session-b");
75
76
console.log(sessionA === sessionB); // false - different IDs
77
```
78
79
## Use Cases
80
81
### External ID Correlation
82
83
Correlate external system IDs with Langfuse traces.
84
85
```typescript
86
import { createTraceId, startObservation } from '@langfuse/tracing';
87
88
async function processExternalRequest(externalRequestId: string) {
89
// Generate deterministic trace ID from external ID
90
const traceId = await createTraceId(externalRequestId);
91
92
// Create observation with custom trace ID
93
const span = startObservation('process-request', {
94
input: { externalRequestId }
95
}, {
96
parentSpanContext: {
97
traceId: traceId,
98
spanId: '0123456789abcdef',
99
traceFlags: 1
100
}
101
});
102
103
// Process request...
104
const result = await handleRequest(externalRequestId);
105
106
span.update({ output: result });
107
span.end();
108
109
return result;
110
}
111
112
// Later, score the trace using the external ID
113
async function scoreTrace(externalRequestId: string, score: number) {
114
// Regenerate the same trace ID
115
const traceId = await createTraceId(externalRequestId);
116
117
// Use trace ID to find and score the Langfuse trace
118
await langfuseClient.score({
119
traceId: traceId,
120
name: 'quality',
121
value: score
122
});
123
}
124
125
// Process request
126
await processExternalRequest('ext-12345-67890');
127
128
// Later, score without storing the trace ID
129
await scoreTrace('ext-12345-67890', 0.95);
130
```
131
132
### Session-Based Tracing
133
134
Group operations by session using deterministic trace IDs.
135
136
```typescript
137
import { createTraceId, startObservation } from '@langfuse/tracing';
138
139
async function trackUserSession(sessionId: string, action: string) {
140
// All operations in the same session share the same trace ID
141
const traceId = await createTraceId(sessionId);
142
143
const observation = startObservation(action, {
144
input: { sessionId, action }
145
}, {
146
parentSpanContext: {
147
traceId: traceId,
148
spanId: crypto.randomUUID().replace(/-/g, '').slice(0, 16),
149
traceFlags: 1
150
}
151
});
152
153
// Perform action...
154
const result = await performAction(action);
155
156
observation.update({ output: result });
157
observation.end();
158
159
return result;
160
}
161
162
// All these operations share the same trace ID
163
const sessionId = 'session-abc-123';
164
await trackUserSession(sessionId, 'login');
165
await trackUserSession(sessionId, 'view-product');
166
await trackUserSession(sessionId, 'add-to-cart');
167
await trackUserSession(sessionId, 'checkout');
168
```
169
170
### Distributed Tracing
171
172
Propagate deterministic trace IDs across service boundaries.
173
174
```typescript
175
import { createTraceId, startObservation } from '@langfuse/tracing';
176
177
// Service A: API Gateway
178
async function handleApiRequest(requestId: string) {
179
const traceId = await createTraceId(requestId);
180
181
const span = startObservation('api-gateway', {
182
input: { requestId }
183
}, {
184
parentSpanContext: {
185
traceId: traceId,
186
spanId: '0123456789abcdef',
187
traceFlags: 1
188
}
189
});
190
191
// Call downstream service with request ID
192
const result = await fetch('https://service-b.com/process', {
193
method: 'POST',
194
headers: {
195
'X-Request-Id': requestId,
196
'Content-Type': 'application/json'
197
},
198
body: JSON.stringify({ data: 'value' })
199
});
200
201
span.update({ output: result });
202
span.end();
203
204
return result;
205
}
206
207
// Service B: Processing Service
208
async function processRequest(req: Request) {
209
const requestId = req.headers.get('X-Request-Id');
210
211
// Regenerate the same trace ID from request ID
212
const traceId = await createTraceId(requestId);
213
214
const span = startObservation('process-request', {
215
input: { requestId }
216
}, {
217
parentSpanContext: {
218
traceId: traceId,
219
spanId: '123456789abcdef0',
220
traceFlags: 1
221
}
222
});
223
224
// Process...
225
const result = await process();
226
227
span.update({ output: result });
228
span.end();
229
230
return result;
231
}
232
```
233
234
### Conversation Threading
235
236
Link multiple conversation turns using deterministic trace IDs.
237
238
```typescript
239
import { createTraceId, startObservation } from '@langfuse/tracing';
240
241
async function handleConversationTurn(
242
conversationId: string,
243
turnNumber: number,
244
userMessage: string
245
) {
246
// All turns in conversation share the same trace ID
247
const traceId = await createTraceId(conversationId);
248
249
const generation = startObservation(`turn-${turnNumber}`, {
250
input: { turnNumber, userMessage },
251
model: 'gpt-4'
252
}, {
253
asType: 'generation',
254
parentSpanContext: {
255
traceId: traceId,
256
spanId: crypto.randomUUID().replace(/-/g, '').slice(0, 16),
257
traceFlags: 1
258
}
259
});
260
261
const response = await llm.chat([
262
{ role: 'user', content: userMessage }
263
]);
264
265
generation.update({
266
output: response,
267
usageDetails: { totalTokens: response.usage.totalTokens }
268
});
269
generation.end();
270
271
return response;
272
}
273
274
// All turns in this conversation share the same trace
275
const conversationId = 'conv-abc-123';
276
await handleConversationTurn(conversationId, 1, 'What is AI?');
277
await handleConversationTurn(conversationId, 2, 'Tell me more');
278
await handleConversationTurn(conversationId, 3, 'Give an example');
279
```
280
281
### Batch Processing
282
283
Group batch items under a single trace using deterministic IDs.
284
285
```typescript
286
import { createTraceId, startObservation } from '@langfuse/tracing';
287
288
async function processBatch(batchId: string, items: any[]) {
289
// All items in batch share the same trace ID
290
const traceId = await createTraceId(batchId);
291
292
for (const [index, item] of items.entries()) {
293
const observation = startObservation(`item-${index}`, {
294
input: { batchId, itemId: item.id, index }
295
}, {
296
parentSpanContext: {
297
traceId: traceId,
298
spanId: crypto.randomUUID().replace(/-/g, '').slice(0, 16),
299
traceFlags: 1
300
}
301
});
302
303
const result = await processItem(item);
304
305
observation.update({ output: result });
306
observation.end();
307
}
308
}
309
310
// All items in this batch share the same trace ID
311
await processBatch('batch-2024-01-01', items);
312
```
313
314
### Testing and Debugging
315
316
Generate predictable trace IDs for testing.
317
318
```typescript
319
import { createTraceId, startObservation } from '@langfuse/tracing';
320
321
describe('Tracing tests', () => {
322
it('should generate consistent trace IDs', async () => {
323
const seed = 'test-seed-123';
324
325
const traceId1 = await createTraceId(seed);
326
const traceId2 = await createTraceId(seed);
327
328
expect(traceId1).toBe(traceId2);
329
});
330
331
it('should create observations with custom trace ID', async () => {
332
const testTraceId = await createTraceId('test-trace');
333
334
const observation = startObservation('test-operation', {
335
input: { test: true }
336
}, {
337
parentSpanContext: {
338
traceId: testTraceId,
339
spanId: '0123456789abcdef',
340
traceFlags: 1
341
}
342
});
343
344
expect(observation.traceId).toBe(testTraceId);
345
observation.end();
346
});
347
});
348
```
349
350
## Implementation Details
351
352
### SHA-256 Hashing
353
354
Deterministic trace IDs are generated using SHA-256 hashing:
355
356
```typescript
357
// Internal implementation (simplified)
358
async function createTraceId(seed?: string): Promise<string> {
359
if (seed) {
360
// Encode seed as UTF-8
361
const data = new TextEncoder().encode(seed);
362
363
// Generate SHA-256 hash
364
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
365
366
// Convert to hex string and take first 32 characters
367
const hashArray = new Uint8Array(hashBuffer);
368
const hexString = Array.from(hashArray)
369
.map(b => b.toString(16).padStart(2, "0"))
370
.join("");
371
372
return hexString.slice(0, 32);
373
}
374
375
// Random generation using crypto.getRandomValues
376
const randomValues = crypto.getRandomValues(new Uint8Array(16));
377
return Array.from(randomValues)
378
.map(b => b.toString(16).padStart(2, "0"))
379
.join("");
380
}
381
```
382
383
### Collision Probability
384
385
Random trace IDs use 128 bits of entropy, making collisions extremely unlikely:
386
387
```typescript
388
// Collision probability calculation
389
// 32 hex characters = 128 bits = 2^128 possible values
390
// Probability of collision: ~1 in 3.4 × 10^38
391
392
const randomId1 = await createTraceId();
393
const randomId2 = await createTraceId();
394
// Virtually guaranteed to be different
395
```
396
397
### Seed Consistency
398
399
The same seed always produces the same trace ID across all platforms:
400
401
```typescript
402
// These will always produce identical trace IDs
403
const nodeTraceId = await createTraceId("my-seed"); // Node.js
404
const browserTraceId = await createTraceId("my-seed"); // Browser
405
const workerTraceId = await createTraceId("my-seed"); // Worker
406
407
// All equal: nodeTraceId === browserTraceId === workerTraceId
408
```
409
410
## Advanced Patterns
411
412
### Hierarchical IDs
413
414
Create hierarchical trace ID structure using seed composition.
415
416
```typescript
417
async function createHierarchicalTrace(
418
organizationId: string,
419
projectId: string,
420
requestId: string
421
) {
422
// Compose seed from hierarchy
423
const seed = `${organizationId}:${projectId}:${requestId}`;
424
const traceId = await createTraceId(seed);
425
426
// All operations with same hierarchy share trace ID
427
return traceId;
428
}
429
430
const traceId = await createHierarchicalTrace(
431
'org-123',
432
'proj-456',
433
'req-789'
434
);
435
```
436
437
### Time-Bucketed Traces
438
439
Group operations by time windows using date-based seeds.
440
441
```typescript
442
async function createTimeBucketedTrace(
443
userId: string,
444
bucketSizeMs: number = 3600000 // 1 hour
445
) {
446
const now = Date.now();
447
const bucket = Math.floor(now / bucketSizeMs);
448
449
// All operations in same time bucket share trace ID
450
const seed = `${userId}:${bucket}`;
451
return await createTraceId(seed);
452
}
453
454
// All operations in same hour share trace ID
455
const traceId = await createTimeBucketedTrace('user-123');
456
```
457
458
### Multi-Tenant Isolation
459
460
Ensure trace ID uniqueness per tenant.
461
462
```typescript
463
async function createTenantTrace(
464
tenantId: string,
465
resourceType: string,
466
resourceId: string
467
) {
468
// Include tenant in seed for isolation
469
const seed = `tenant:${tenantId}:${resourceType}:${resourceId}`;
470
return await createTraceId(seed);
471
}
472
473
const traceId = await createTenantTrace(
474
'tenant-abc',
475
'order',
476
'order-123'
477
);
478
```
479
480
## Best Practices
481
482
### Use Deterministic IDs for Correlation
483
484
Use seeded generation when you need to correlate with external systems.
485
486
```typescript
487
// Good: Deterministic for correlation
488
const externalId = 'payment-12345';
489
const traceId = await createTraceId(externalId);
490
491
// Later, retrieve trace using external ID
492
const sameTraceId = await createTraceId(externalId);
493
```
494
495
### Use Random IDs for Independence
496
497
Use random generation for independent, uncorrelated operations.
498
499
```typescript
500
// Good: Random for independent operations
501
const traceId = await createTraceId();
502
503
const observation = startObservation('one-time-operation', {
504
input: { data: 'value' }
505
}, {
506
parentSpanContext: {
507
traceId: traceId,
508
spanId: '0123456789abcdef',
509
traceFlags: 1
510
}
511
});
512
```
513
514
### Include Context in Seeds
515
516
Make seeds descriptive and include relevant context.
517
518
```typescript
519
// Good: Descriptive seed with context
520
const seed = `user:${userId}:session:${sessionId}:request:${requestId}`;
521
const traceId = await createTraceId(seed);
522
523
// Avoid: Generic seed
524
const traceId = await createTraceId(userId); // May collide across contexts
525
```
526
527
### Validate Seed Uniqueness
528
529
Ensure seeds are unique enough to avoid collisions.
530
531
```typescript
532
// Good: Unique per operation
533
const seed = `${resourceType}:${resourceId}:${timestamp}`;
534
535
// Risky: May collide
536
const seed = resourceId; // If resourceId repeats across types
537
```
538
539
### Document Seed Format
540
541
Document seed formats for consistent regeneration.
542
543
```typescript
544
/**
545
* Creates a trace ID for user session operations.
546
*
547
* Seed format: "session:{sessionId}:user:{userId}"
548
*
549
* @example
550
* const traceId = await createSessionTraceId('sess-123', 'user-456');
551
* // Can regenerate later using same IDs
552
*/
553
async function createSessionTraceId(
554
sessionId: string,
555
userId: string
556
): Promise<string> {
557
return await createTraceId(`session:${sessionId}:user:${userId}`);
558
}
559
```
560
561
### Handle Async Nature
562
563
Remember that `createTraceId()` is async and returns a Promise.
564
565
```typescript
566
// Good: Await the result
567
const traceId = await createTraceId("my-seed");
568
569
// Wrong: Missing await
570
const traceId = createTraceId("my-seed"); // Promise object, not string
571
572
// Good: Use in async context
573
async function createTrace() {
574
const traceId = await createTraceId();
575
return traceId;
576
}
577
```
578
579
### Cache Generated IDs
580
581
Cache deterministic trace IDs to avoid repeated hashing.
582
583
```typescript
584
const traceIdCache = new Map<string, string>();
585
586
async function getCachedTraceId(seed: string): Promise<string> {
587
if (traceIdCache.has(seed)) {
588
return traceIdCache.get(seed)!;
589
}
590
591
const traceId = await createTraceId(seed);
592
traceIdCache.set(seed, traceId);
593
return traceId;
594
}
595
596
// Faster for repeated calls with same seed
597
const traceId1 = await getCachedTraceId('session-123');
598
const traceId2 = await getCachedTraceId('session-123'); // From cache
599
```
600