Documentation Index Fetch the complete documentation index at: https://mintlify.com/getsentry/sentry-javascript/llms.txt
Use this file to discover all available pages before exploring further.
Performance monitoring helps identify slow operations and optimize user experience while minimizing overhead on your application.
Browser Applications
import * as Sentry from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
Sentry . browserTracingIntegration (),
],
tracesSampleRate: 0.1 , // Capture 10% of transactions
});
Node.js Applications
import * as Sentry from '@sentry/node' ;
// MUST be first import
Sentry . init ({
dsn: '__DSN__' ,
tracesSampleRate: 0.1 ,
});
// Now import other modules
import express from 'express' ;
For Node.js SDK v8+, you MUST initialize Sentry before any other imports for OpenTelemetry instrumentation to work.
Instrumentation
Automatic Instrumentation
The SDK automatically instruments:
Browser:
Page load transactions
Navigation transactions
Fetch/XHR requests
User interactions (clicks, form inputs)
Web Vitals (LCP, FID, CLS, INP, TTFB)
Node.js:
HTTP/HTTPS requests
Express.js routes
Database queries (Prisma, MongoDB, MySQL, PostgreSQL)
GraphQL operations
Redis operations
// Browser
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
Sentry . browserTracingIntegration ({
// Customize instrumentation
traceFetch: true ,
traceXHR: true ,
enableLongAnimationFrame: true ,
}),
],
});
// Node.js - integrations are auto-enabled
Sentry . init ({
dsn: '__DSN__' ,
tracesSampleRate: 0.1 ,
// These are enabled by default:
// - httpIntegration()
// - expressIntegration()
// - prismaIntegration()
// - etc.
});
Manual Instrumentation
Create custom spans for specific operations:
import { startSpan } from '@sentry/browser' ;
const result = await startSpan (
{
name: 'complex-calculation' ,
op: 'function' ,
attributes: {
'calc.type' : 'fibonacci' ,
'calc.input' : n ,
},
},
async ( span ) => {
const result = await fibonacci ( n );
span . setAttribute ( 'calc.result' , result );
return result ;
}
);
Nested Spans
Track sub-operations:
await startSpan (
{ name: 'process-order' , op: 'task' },
async ( parentSpan ) => {
await startSpan (
{ name: 'validate-order' , op: 'validation' },
async () => {
await validateOrder ( order );
}
);
await startSpan (
{ name: 'charge-payment' , op: 'payment' },
async () => {
await chargePayment ( order );
}
);
await startSpan (
{ name: 'create-shipment' , op: 'logistics' },
async () => {
await createShipment ( order );
}
);
}
);
Controlling Span Creation
HTTP Instrumentation
Control which requests create spans:
import { httpIntegration } from '@sentry/node' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
httpIntegration ({
tracing: {
// Don't create spans for certain URLs
shouldCreateSpanForRequest : ( url ) => {
return ! url . includes ( '/health' ) &&
! url . includes ( '/metrics' );
},
},
}),
],
});
Browser Request Instrumentation
import { browserTracingIntegration } from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
browserTracingIntegration ({
shouldCreateSpanForRequest : ( url ) => {
// Don't trace analytics or ads
return ! url . match ( /google-analytics | doubleclick/ );
},
}),
],
});
Trace Propagation
Control distributed tracing headers:
Sentry . init ({
dsn: '__DSN__' ,
// Propagate to same origin by default
// Customize for specific targets:
tracePropagationTargets: [
'localhost' ,
/ ^ https: \/\/ api \. myapp \. com/ ,
/ ^ \/ api \/ / , // Same-origin API routes
],
});
In v8+, trace propagation defaults to same-origin requests. Only set tracePropagationTargets for cross-origin distributed tracing.
Web Vitals
Monitor Core Web Vitals automatically:
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
Sentry . browserTracingIntegration (),
],
});
// Captured automatically:
// - Largest Contentful Paint (LCP)
// - First Input Delay (FID) - deprecated, replaced by INP in v10+
// - Cumulative Layout Shift (CLS)
// - Interaction to Next Paint (INP)
// - Time to First Byte (TTFB)
Custom Measurements
Add custom performance measurements:
import { setMeasurement , startSpan } from '@sentry/browser' ;
startSpan ({ name: 'page-load' }, () => {
// Custom measurement
setMeasurement ( 'custom.metric' , 123 , 'millisecond' );
// Multiple measurements
setMeasurement ( 'bundle.size' , 450 , 'kilobyte' );
setMeasurement ( 'api.calls' , 5 , 'none' );
});
Transaction Naming
Browser Route Naming
import { browserTracingIntegration } from '@sentry/react' ;
import { useEffect } from 'react' ;
import { useLocation } from 'react-router-dom' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
browserTracingIntegration (),
],
});
// React Router integration handles naming automatically
Custom Transaction Names
import { getActiveSpan , getRootSpan } from '@sentry/browser' ;
// Update transaction name dynamically
const activeSpan = getActiveSpan ();
if ( activeSpan ) {
const rootSpan = getRootSpan ( activeSpan );
rootSpan . updateName ( 'Custom Transaction Name' );
}
Node.js Route Naming
import express from 'express' ;
const app = express ();
app . get ( '/users/:id' , ( req , res ) => {
// Automatically named: GET /users/:id
res . json ({ id: req . params . id });
});
Sampling Strategies
Prioritize Important Transactions
Sentry . init ({
dsn: '__DSN__' ,
tracesSampler : ( samplingContext ) => {
// Always sample checkout flows
if ( samplingContext . name ?. includes ( '/checkout' )) {
return 1.0 ;
}
// Sample API calls moderately
if ( samplingContext . name ?. startsWith ( '/api/' )) {
return 0.2 ;
}
// Don't sample health checks
if ( samplingContext . name === '/health' ) {
return 0 ;
}
// Default sampling
return 0.05 ;
},
});
Environment-Based Sampling
const isProd = process . env . NODE_ENV === 'production' ;
Sentry . init ({
dsn: '__DSN__' ,
tracesSampleRate: isProd ? 0.05 : 1.0 ,
});
Disable Unnecessary Integrations
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
// Only enable what you need
Sentry . browserTracingIntegration ({
// Disable interaction tracking if not needed
traceFetch: true ,
traceXHR: true ,
}),
],
});
Limit Breadcrumb Collection
import { breadcrumbsIntegration } from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
breadcrumbsIntegration ({
console: false , // Disable console breadcrumbs
dom: true ,
fetch: true ,
history: true ,
sentry: false ,
xhr: true ,
}),
],
maxBreadcrumbs: 50 , // Default is 100
});
Selective Instrumentation
import { httpIntegration } from '@sentry/node' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
httpIntegration ({
// Disable if you don't need HTTP spans
spans: false ,
}),
],
});
Framework-Specific Optimizations
React
import * as Sentry from '@sentry/react' ;
import {
createRoutesFromChildren ,
matchRoutes ,
useLocation ,
useNavigationType ,
} from 'react-router-dom' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
Sentry . reactRouterV6BrowserTracingIntegration ({
useEffect: React . useEffect ,
useLocation ,
useNavigationType ,
createRoutesFromChildren ,
matchRoutes ,
}),
],
tracesSampleRate: 0.1 ,
});
Next.js
Next.js SDK handles instrumentation automatically:
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs' ;
Sentry . init ({
dsn: '__DSN__' ,
tracesSampleRate: 0.1 ,
// Browser tracing is automatic
});
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs' ;
Sentry . init ({
dsn: '__DSN__' ,
tracesSampleRate: 0.1 ,
// Server instrumentation is automatic
});
Vue
import * as Sentry from '@sentry/vue' ;
Sentry . init ({
app ,
dsn: '__DSN__' ,
integrations: [
Sentry . browserTracingIntegration ({
router , // Pass Vue Router instance
}),
],
tracesSampleRate: 0.1 ,
});
Database Query Instrumentation
Prisma
import { prismaIntegration } from '@sentry/node' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
prismaIntegration (),
],
});
// Queries are automatically instrumented
const users = await prisma . user . findMany ();
MongoDB (Mongoose)
import { mongooseIntegration } from '@sentry/node' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
mongooseIntegration (),
],
});
Best Practices
Use lower sampling rates in production
High-traffic applications should use lower sample rates: const sampleRate = process . env . NODE_ENV === 'production' ? 0.05 : 1.0 ;
Sentry . init ({
dsn: '__DSN__' ,
tracesSampleRate: sampleRate ,
});
Don't sample health checks or metrics endpoints
These create noise without value: tracesSampler : ( context ) => {
if ( context . name ?. match ( / \/ ( health | metrics | ping ) / )) {
return 0 ;
}
return 0.1 ;
}
Use span operations correctly
Set appropriate op values for better organization: startSpan ({ name: 'db-query' , op: 'db.query' }, () => {});
startSpan ({ name: 'api-call' , op: 'http.client' }, () => {});
startSpan ({ name: 'render' , op: 'ui.render' }, () => {});
Avoid creating too many spans
Too many spans can increase overhead. Focus on meaningful operations: // ❌ Too granular
for ( const item of items ) {
startSpan ({ name: 'process-item' }, () => processItem ( item ));
}
// ✅ Better
startSpan ({ name: 'process-items' }, () => {
items . forEach ( processItem );
});
Set meaningful span attributes
Add context to help debug performance issues: startSpan (
{
name: 'fetch-user-data' ,
op: 'http.client' ,
attributes: {
'http.method' : 'GET' ,
'http.url' : '/api/users/123' ,
'user.id' : '123' ,
},
},
() => {}
);
Check SDK Overhead
const start = performance . now ();
// Your operation
await myOperation ();
const duration = performance . now () - start ;
console . log ( 'Operation duration:' , duration );
Profile Mode
Enable profiling for deeper insights:
import { browserProfilingIntegration } from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
browserProfilingIntegration (),
],
tracesSampleRate: 0.1 ,
profilesSampleRate: 0.1 , // Relative to traces
});
Complete Example
import * as Sentry from '@sentry/browser' ;
import { startSpan } from '@sentry/browser' ;
const environment = process . env . NODE_ENV ;
const isProd = environment === 'production' ;
Sentry . init ({
dsn: '__DSN__' ,
environment ,
integrations: [
Sentry . browserTracingIntegration ({
// Customize what's traced
traceFetch: true ,
traceXHR: true ,
enableLongAnimationFrame: true ,
// Filter requests
shouldCreateSpanForRequest : ( url ) => {
return ! url . match ( / ( \. png | \. jpg | analytics | ads ) / );
},
}),
],
// Sampling strategy
tracesSampler : ( context ) => {
// Never sample health checks
if ( context . name === '/health' ) return 0 ;
// Always sample checkout
if ( context . name ?. includes ( '/checkout' )) return 1.0 ;
// Production: low rate
// Development: high rate
return isProd ? 0.05 : 1.0 ;
},
// Propagate to your API
tracePropagationTargets: [
'localhost' ,
/ ^ https: \/\/ api \. myapp \. com/ ,
],
// Reduce breadcrumbs
maxBreadcrumbs: 50 ,
});
// Manual instrumentation example
export async function complexOperation ( userId ) {
return await startSpan (
{
name: 'complex-operation' ,
op: 'task' ,
attributes: { 'user.id' : userId },
},
async ( span ) => {
// Step 1
await startSpan (
{ name: 'fetch-user' , op: 'http.client' },
async () => {
const user = await fetchUser ( userId );
span . setAttribute ( 'user.role' , user . role );
return user ;
}
);
// Step 2
await startSpan (
{ name: 'process-data' , op: 'function' },
async () => {
return await processUserData ( user );
}
);
}
);
}
Next Steps
Bundle Size Optimization Reduce SDK bundle size impact
Source Maps Configure source maps for production