0
# Performance Monitoring
1
2
Browser performance monitoring with distributed tracing capabilities. The Sentry Browser SDK provides comprehensive performance tracking for web applications including page loads, navigation, user interactions, and custom operations.
3
4
## Capabilities
5
6
### Span Management
7
8
Create and manage performance spans to track operations.
9
10
```typescript { .api }
11
/**
12
* Start a new span to track an operation
13
* @param context - Span context configuration
14
* @returns Span instance for the created span
15
*/
16
function startSpan<T>(context: SpanContext, callback: (span: Span) => T): T;
17
18
/**
19
* Start an inactive span that must be manually activated
20
* @param context - Span context configuration
21
* @returns Span instance
22
*/
23
function startInactiveSpan(context: SpanContext): Span;
24
25
/**
26
* Start a span with manual lifecycle control
27
* @param context - Span context configuration
28
* @returns Span instance that must be manually ended
29
*/
30
function startSpanManual(context: SpanContext): Span;
31
```
32
33
**Usage Examples:**
34
35
```typescript
36
import { startSpan, startInactiveSpan } from "@sentry/browser";
37
38
// Automatic span management
39
const result = startSpan(
40
{ name: "data_processing", op: "function" },
41
(span) => {
42
span.setTag("data_type", "user_analytics");
43
span.setData("record_count", 1000);
44
45
// Your operation here
46
const processedData = processAnalyticsData();
47
48
span.setData("processed_count", processedData.length);
49
return processedData;
50
}
51
);
52
53
// Manual span management
54
const span = startInactiveSpan({
55
name: "file_upload",
56
op: "http.client",
57
});
58
59
span.setTag("file_type", "image");
60
span.setData("file_size", fileSize);
61
62
try {
63
const response = await uploadFile(file);
64
span.setData("response_size", response.size);
65
span.setStatus("ok");
66
} catch (error) {
67
span.setStatus("internal_error");
68
throw error;
69
} finally {
70
span.end();
71
}
72
```
73
74
### Active Span Management
75
76
Work with the currently active span.
77
78
```typescript { .api }
79
/**
80
* Get the currently active span
81
* @returns Active span instance or undefined if no span is active
82
*/
83
function getActiveSpan(): Span | undefined;
84
85
/**
86
* Get the root span of the current trace
87
* @returns Root span instance or undefined
88
*/
89
function getRootSpan(): Span | undefined;
90
91
/**
92
* Execute callback with a specific span as the active span
93
* @param span - Span to make active (or null to clear active span)
94
* @param callback - Function to execute with the active span
95
* @returns Result of the callback function
96
*/
97
function withActiveSpan<T>(span: Span | null, callback: () => T): T;
98
```
99
100
**Usage Examples:**
101
102
```typescript
103
import { getActiveSpan, withActiveSpan, startSpan } from "@sentry/browser";
104
105
// Get current active span
106
const currentSpan = getActiveSpan();
107
if (currentSpan) {
108
currentSpan.setTag("has_active_span", true);
109
}
110
111
// Execute code with specific active span
112
const parentSpan = startInactiveSpan({ name: "parent_operation" });
113
114
withActiveSpan(parentSpan, () => {
115
// Any spans created here will be children of parentSpan
116
startSpan({ name: "child_operation" }, () => {
117
// This span is a child of parentSpan
118
performChildOperation();
119
});
120
});
121
```
122
123
### Trace Management
124
125
Manage distributed traces across different contexts.
126
127
```typescript { .api }
128
/**
129
* Start a new trace, isolating it from any existing trace
130
* @param callback - Function to execute in the new trace context
131
* @returns Result of the callback function
132
*/
133
function startNewTrace<T>(callback: () => T): T;
134
135
/**
136
* Continue a trace from incoming headers (e.g., HTTP requests)
137
* @param headers - Headers containing trace information
138
* @param callback - Function to execute in the continued trace context
139
* @returns Result of the callback function
140
*/
141
function continueTrace<T>(
142
headers: { [key: string]: string | string[] | undefined },
143
callback: () => T
144
): T;
145
146
/**
147
* Get trace data for the current span/transaction
148
* @returns Object containing trace and baggage headers
149
*/
150
function getTraceData(): { "sentry-trace"?: string; baggage?: string };
151
152
/**
153
* Suppress tracing for the given callback
154
* @param callback - Function to execute without tracing
155
* @returns Result of the callback function
156
*/
157
function suppressTracing<T>(callback: () => T): T;
158
```
159
160
**Usage Examples:**
161
162
```typescript
163
import { startNewTrace, continueTrace, getTraceData } from "@sentry/browser";
164
165
// Start completely new trace
166
startNewTrace(() => {
167
// This creates a new trace, disconnected from any parent
168
startSpan({ name: "independent_operation" }, () => {
169
performIndependentWork();
170
});
171
});
172
173
// Continue trace from incoming request
174
function handleIncomingRequest(headers: Record<string, string>) {
175
continueTrace(headers, () => {
176
startSpan({ name: "request_handler" }, () => {
177
processRequest();
178
});
179
});
180
}
181
182
// Get trace data for outgoing requests
183
const traceData = getTraceData();
184
fetch("/api/data", {
185
headers: {
186
...traceData, // Includes sentry-trace and baggage headers
187
},
188
});
189
```
190
191
### Span Utilities
192
193
Utility functions for working with spans.
194
195
```typescript { .api }
196
/**
197
* Convert span to JSON representation
198
* @param span - Span to convert
199
* @returns JSON representation of the span
200
*/
201
function spanToJSON(span: Span): SpanJSON;
202
203
/**
204
* Create sentry-trace header from span
205
* @param span - Span to create header from
206
* @returns sentry-trace header value
207
*/
208
function spanToTraceHeader(span: Span): string;
209
210
/**
211
* Create baggage header from span
212
* @param span - Span to create header from
213
* @returns baggage header value
214
*/
215
function spanToBaggageHeader(span: Span): string | undefined;
216
217
/**
218
* Update the name of a span
219
* @param span - Span to update
220
* @param name - New name for the span
221
*/
222
function updateSpanName(span: Span, name: string): void;
223
224
/**
225
* Get all descendant spans of a given span
226
* @param span - Parent span
227
* @returns Array of descendant spans
228
*/
229
function getSpanDescendants(span: Span): Span[];
230
```
231
232
### Performance Measurements
233
234
Set custom performance measurements.
235
236
```typescript { .api }
237
/**
238
* Set a custom measurement on the current transaction
239
* @param name - Measurement name
240
* @param value - Measurement value
241
* @param unit - Measurement unit (optional)
242
*/
243
function setMeasurement(name: string, value: number, unit?: MeasurementUnit): void;
244
```
245
246
**Usage Example:**
247
248
```typescript
249
import { setMeasurement } from "@sentry/browser";
250
251
// Custom performance metrics
252
setMeasurement("custom.database.query.duration", 150, "millisecond");
253
setMeasurement("custom.cache.hit.ratio", 0.85, "ratio");
254
setMeasurement("custom.memory.usage", 1024 * 1024, "byte");
255
```
256
257
### HTTP Status Handling
258
259
Utilities for handling HTTP status codes in spans.
260
261
```typescript { .api }
262
/**
263
* Get span status from HTTP status code
264
* @param httpStatus - HTTP status code
265
* @returns Appropriate span status
266
*/
267
function getSpanStatusFromHttpCode(httpStatus: number): SpanStatus;
268
269
/**
270
* Set HTTP status on a span
271
* @param span - Span to update
272
* @param httpStatus - HTTP status code
273
*/
274
function setHttpStatus(span: Span, httpStatus: number): void;
275
```
276
277
### Browser-Specific Tracing
278
279
Browser-specific performance monitoring integrations.
280
281
```typescript { .api }
282
/**
283
* Create browser tracing integration for automatic performance monitoring
284
* @param options - Configuration options for browser tracing
285
* @returns Browser tracing integration
286
*/
287
function browserTracingIntegration(options?: BrowserTracingOptions): Integration;
288
289
/**
290
* Start a browser navigation span manually
291
* @param context - Navigation span context
292
* @returns Navigation span
293
*/
294
function startBrowserTracingNavigationSpan(context: NavigationSpanContext): Span;
295
296
/**
297
* Start a browser page load span manually
298
* @param context - Page load span context
299
* @returns Page load span
300
*/
301
function startBrowserTracingPageLoadSpan(context: PageLoadSpanContext): Span;
302
```
303
304
**Usage Example:**
305
306
```typescript
307
import { browserTracingIntegration } from "@sentry/browser";
308
309
// Enable automatic browser tracing
310
Sentry.init({
311
dsn: "YOUR_DSN",
312
integrations: [
313
browserTracingIntegration({
314
enableLongTask: true,
315
enableInp: true,
316
enableUserTimingApi: true,
317
tracePropagationTargets: ["localhost", "api.example.com"],
318
}),
319
],
320
tracesSampleRate: 0.1,
321
});
322
```
323
324
### Request Instrumentation
325
326
Instrument outgoing HTTP requests for performance monitoring.
327
328
```typescript { .api }
329
/**
330
* Default options for request instrumentation
331
*/
332
const defaultRequestInstrumentationOptions: RequestInstrumentationOptions;
333
334
/**
335
* Instrument outgoing requests for performance tracking
336
* @param options - Configuration options for request instrumentation
337
*/
338
function instrumentOutgoingRequests(options?: RequestInstrumentationOptions): void;
339
```
340
341
## Types
342
343
### Span Interface
344
345
```typescript { .api }
346
interface Span {
347
/** Set a tag on this span */
348
setTag(key: string, value: string): void;
349
350
/** Set data on this span */
351
setData(key: string, value: any): void;
352
353
/** Set the status of this span */
354
setStatus(status: SpanStatus): void;
355
356
/** Set HTTP status on this span */
357
setHttpStatus(code: number): void;
358
359
/** Update the name of this span */
360
updateName(name: string): void;
361
362
/** End this span */
363
end(timestamp?: number): void;
364
365
/** Get the span context */
366
spanContext(): SpanContext;
367
368
/** Check if span is recording */
369
isRecording(): boolean;
370
371
/** Add an event to this span */
372
addEvent(name: string, attributes?: Record<string, any>, timestamp?: number): void;
373
}
374
```
375
376
### Span Context
377
378
```typescript { .api }
379
interface SpanContext {
380
/** Name of the operation being tracked */
381
name: string;
382
383
/** Operation type (e.g., "http.client", "db.query") */
384
op?: string;
385
386
/** Description of the operation */
387
description?: string;
388
389
/** Start timestamp */
390
startTimestamp?: number;
391
392
/** End timestamp */
393
endTimestamp?: number;
394
395
/** Parent span ID */
396
parentSpanId?: string;
397
398
/** Trace ID */
399
traceId?: string;
400
401
/** Span ID */
402
spanId?: string;
403
404
/** Tags for this span */
405
tags?: Record<string, string>;
406
407
/** Data for this span */
408
data?: Record<string, any>;
409
410
/** Origin of this span */
411
origin?: string;
412
413
/** Instrumentation library info */
414
instrumenter?: string;
415
}
416
```
417
418
### Span Status
419
420
```typescript { .api }
421
type SpanStatus =
422
| "ok"
423
| "cancelled"
424
| "unknown"
425
| "invalid_argument"
426
| "deadline_exceeded"
427
| "not_found"
428
| "already_exists"
429
| "permission_denied"
430
| "resource_exhausted"
431
| "failed_precondition"
432
| "aborted"
433
| "out_of_range"
434
| "unimplemented"
435
| "internal_error"
436
| "unavailable"
437
| "data_loss"
438
| "unauthenticated";
439
```
440
441
### Browser Tracing Options
442
443
```typescript { .api }
444
interface BrowserTracingOptions {
445
/** Enable Long Task API instrumentation */
446
enableLongTask?: boolean;
447
448
/** Enable Interaction to Next Paint (INP) tracking */
449
enableInp?: boolean;
450
451
/** Enable User Timing API marks and measures */
452
enableUserTimingApi?: boolean;
453
454
/** URLs to propagate trace headers to */
455
tracePropagationTargets?: (string | RegExp)[];
456
457
/** Sample rate for navigation transactions */
458
routingInstrumentation?: (
459
customStartTransaction: (context: TransactionContext) => Transaction,
460
startTransactionOnPageLoad?: boolean,
461
startTransactionOnLocationChange?: boolean
462
) => void;
463
464
/** Maximum transaction duration in seconds */
465
maxTransactionDuration?: number;
466
467
/** Idle timeout for transactions in seconds */
468
idleTimeout?: number;
469
470
/** Enable heart beat for long running transactions */
471
heartbeatInterval?: number;
472
473
/** Mark transactions as failed if they exceed this duration */
474
finalTimeout?: number;
475
476
/** Enable automatic span creation for fetch requests */
477
traceFetch?: boolean;
478
479
/** Enable automatic span creation for XHR requests */
480
traceXHR?: boolean;
481
482
/** Before navigation callback */
483
beforeNavigate?: (context: TransactionContext) => TransactionContext | undefined;
484
}
485
```
486
487
### Request Instrumentation Options
488
489
```typescript { .api }
490
interface RequestInstrumentationOptions {
491
/** URLs to track for performance */
492
tracePropagationTargets?: (string | RegExp)[];
493
494
/** Enable tracing for fetch requests */
495
traceFetch?: boolean;
496
497
/** Enable tracing for XHR requests */
498
traceXHR?: boolean;
499
500
/** Function to determine if request should be traced */
501
shouldCreateSpanForRequest?: (url: string) => boolean;
502
503
/** Callback before creating span for request */
504
beforeSpan?: (span: Span, request: { method?: string; url: string }) => void;
505
}
506
```
507
508
### Measurement Unit
509
510
```typescript { .api }
511
type MeasurementUnit =
512
| "nanosecond"
513
| "microsecond"
514
| "millisecond"
515
| "second"
516
| "minute"
517
| "hour"
518
| "day"
519
| "week"
520
| "byte"
521
| "kilobyte"
522
| "kibibyte"
523
| "megabyte"
524
| "mebibyte"
525
| "gigabyte"
526
| "gibibyte"
527
| "terabyte"
528
| "tebibyte"
529
| "petabyte"
530
| "pebibyte"
531
| "bit"
532
| "kilobit"
533
| "megabit"
534
| "gigabit"
535
| "terabit"
536
| "petabit"
537
| "percent"
538
| "ratio"
539
| "none";
540
```
541
542
## Automatic Instrumentation
543
544
The browser tracing integration automatically creates spans for:
545
546
- **Page loads**: Complete page load performance
547
- **Navigation**: Client-side route changes
548
- **HTTP requests**: Fetch and XHR requests
549
- **User interactions**: Click events and form submissions
550
- **Long tasks**: Tasks that block the main thread
551
- **Layout shifts**: Cumulative Layout Shift (CLS) tracking
552
- **Paint timings**: First Paint, First Contentful Paint
553
- **Web Vitals**: LCP, FID, CLS metrics
554
555
## Custom Instrumentation Patterns
556
557
### Database Operations
558
559
```typescript
560
import { startSpan } from "@sentry/browser";
561
562
async function queryDatabase(query: string) {
563
return startSpan(
564
{
565
name: "db.query",
566
op: "db",
567
data: {
568
query: query.substring(0, 100), // Truncate long queries
569
db_type: "postgresql",
570
},
571
},
572
async (span) => {
573
try {
574
const result = await executeQuery(query);
575
span.setData("row_count", result.rows.length);
576
span.setStatus("ok");
577
return result;
578
} catch (error) {
579
span.setStatus("internal_error");
580
throw error;
581
}
582
}
583
);
584
}
585
```
586
587
### API Calls
588
589
```typescript
590
import { startSpan, getTraceData } from "@sentry/browser";
591
592
async function callExternalAPI(endpoint: string, data: any) {
593
return startSpan(
594
{
595
name: `API ${endpoint}`,
596
op: "http.client",
597
data: { endpoint, method: "POST" },
598
},
599
async (span) => {
600
const traceHeaders = getTraceData();
601
602
try {
603
const response = await fetch(endpoint, {
604
method: "POST",
605
headers: {
606
"Content-Type": "application/json",
607
...traceHeaders,
608
},
609
body: JSON.stringify(data),
610
});
611
612
span.setHttpStatus(response.status);
613
span.setData("response_size", response.headers.get("content-length"));
614
615
return response.json();
616
} catch (error) {
617
span.setStatus("internal_error");
618
throw error;
619
}
620
}
621
);
622
}
623
```
624
625
### Background Tasks
626
627
```typescript
628
import { startSpan } from "@sentry/browser";
629
630
function processInBackground(items: any[]) {
631
startSpan(
632
{
633
name: "background_processing",
634
op: "task",
635
data: { item_count: items.length },
636
},
637
(span) => {
638
let processed = 0;
639
640
items.forEach((item, index) => {
641
try {
642
processItem(item);
643
processed++;
644
} catch (error) {
645
span.setTag("has_errors", "true");
646
// Continue processing other items
647
}
648
649
// Update progress
650
if (index % 100 === 0) {
651
span.setData("progress", `${index}/${items.length}`);
652
}
653
});
654
655
span.setData("processed_count", processed);
656
span.setData("failed_count", items.length - processed);
657
}
658
);
659
}
660
```