The addBreadcrumb function records breadcrumbs that create a trail of events leading up to an error or issue.
Function Signature
export function addBreadcrumb(
breadcrumb: Breadcrumb,
hint?: BreadcrumbHint
): void
Parameters
Additional context about the breadcrumb for filtering or processing.
Breadcrumb Structure
export interface Breadcrumb {
type?: string;
level?: SeverityLevel;
event_id?: string;
category?: string;
message?: string;
data?: { [key: string]: any };
timestamp?: number;
}
The type of breadcrumb: 'default', 'debug', 'error', 'navigation', 'http', 'info', 'query', 'transaction', 'ui', 'user'.
The severity level: 'fatal', 'error', 'warning', 'info', 'debug', or 'log'. Defaults to 'info'.
A dotted string indicating what the breadcrumb is or where it comes from (e.g., 'ui.click', 'console.log', 'http.request').
A human-readable message for the breadcrumb.
Arbitrary data associated with the breadcrumb.
Unix timestamp in seconds when the breadcrumb occurred.
Basic Usage
import * as Sentry from '@sentry/node';
Sentry.addBreadcrumb({
category: 'auth',
message: 'User logged in',
level: 'info'
});
Breadcrumb Types
Navigation Breadcrumbs
import * as Sentry from '@sentry/node';
Sentry.addBreadcrumb({
type: 'navigation',
category: 'navigation',
message: 'User navigated to /dashboard',
data: {
from: '/home',
to: '/dashboard'
},
level: 'info'
});
HTTP Request Breadcrumbs
import * as Sentry from '@sentry/node';
Sentry.addBreadcrumb({
type: 'http',
category: 'fetch',
message: 'GET /api/users',
data: {
url: 'https://api.example.com/users',
method: 'GET',
status_code: 200,
request_body_size: 0,
response_body_size: 1024
},
level: 'info',
timestamp: Date.now() / 1000
});
User Action Breadcrumbs
import * as Sentry from '@sentry/node';
Sentry.addBreadcrumb({
type: 'user',
category: 'ui.click',
message: 'User clicked checkout button',
data: {
button_id: 'checkout-btn',
cart_items: 3,
total_amount: 99.99
},
level: 'info'
});
Database Query Breadcrumbs
import * as Sentry from '@sentry/node';
Sentry.addBreadcrumb({
type: 'query',
category: 'db.query',
message: 'SELECT * FROM users WHERE id = $1',
data: {
'db.system': 'postgresql',
'db.name': 'myapp',
'db.statement': 'SELECT * FROM users WHERE id = $1',
duration_ms: 15
},
level: 'info'
});
Console Log Breadcrumbs
import * as Sentry from '@sentry/node';
Sentry.addBreadcrumb({
type: 'debug',
category: 'console',
message: 'Processing payment...',
level: 'debug',
data: {
logger: 'console',
arguments: ['Processing payment for order', '12345']
}
});
Error Breadcrumbs
import * as Sentry from '@sentry/node';
Sentry.addBreadcrumb({
type: 'error',
category: 'exception',
message: 'TypeError: Cannot read property of undefined',
level: 'error',
data: {
error_name: 'TypeError',
error_message: 'Cannot read property of undefined'
}
});
Implementation Details
From packages/core/src/breadcrumbs.ts:
export function addBreadcrumb(
breadcrumb: Breadcrumb,
hint?: BreadcrumbHint
): void {
const client = getClient();
const isolationScope = getIsolationScope();
if (!client) return;
const {
beforeBreadcrumb = null,
maxBreadcrumbs = DEFAULT_BREADCRUMBS
} = client.getOptions();
if (maxBreadcrumbs <= 0) return;
const timestamp = dateTimestampInSeconds();
const mergedBreadcrumb = { timestamp, ...breadcrumb };
const finalBreadcrumb = beforeBreadcrumb
? consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint))
: mergedBreadcrumb;
if (finalBreadcrumb === null) return;
if (client.emit) {
client.emit('beforeAddBreadcrumb', finalBreadcrumb, hint);
}
isolationScope.addBreadcrumb(finalBreadcrumb, maxBreadcrumbs);
}
Automatic Breadcrumbs
Many integrations automatically add breadcrumbs:
HTTP Integration
import * as Sentry from '@sentry/node';
import { httpIntegration } from '@sentry/node';
Sentry.init({
dsn: 'your-dsn',
integrations: [
httpIntegration({
// Automatically creates breadcrumbs for HTTP requests
breadcrumbs: true
})
]
});
// Breadcrumbs created automatically for:
// - Outgoing HTTP requests
// - Incoming HTTP requests
// - Request/response details
Console Integration
import * as Sentry from '@sentry/node';
import { captureConsoleIntegration } from '@sentry/node';
Sentry.init({
dsn: 'your-dsn',
integrations: [
captureConsoleIntegration({
levels: ['log', 'info', 'warn', 'error']
})
]
});
// Automatically captures console calls as breadcrumbs
console.log('User action'); // Becomes a breadcrumb
Filtering Breadcrumbs
Use beforeBreadcrumb to filter or modify breadcrumbs:
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'your-dsn',
beforeBreadcrumb(breadcrumb, hint) {
// Filter out console breadcrumbs
if (breadcrumb.category === 'console') {
return null;
}
// Scrub sensitive data
if (breadcrumb.data?.url) {
breadcrumb.data.url = breadcrumb.data.url.replace(/token=[^&]+/, 'token=REDACTED');
}
return breadcrumb;
}
});
Advanced Examples
API Call Tracking
import * as Sentry from '@sentry/node';
async function makeApiCall(endpoint: string, options: RequestInit) {
const startTime = Date.now();
Sentry.addBreadcrumb({
type: 'http',
category: 'fetch',
message: `${options.method} ${endpoint}`,
data: {
url: endpoint,
method: options.method
},
level: 'info'
});
try {
const response = await fetch(endpoint, options);
const duration = Date.now() - startTime;
Sentry.addBreadcrumb({
type: 'http',
category: 'fetch',
message: `${options.method} ${endpoint} - ${response.status}`,
data: {
url: endpoint,
method: options.method,
status_code: response.status,
duration_ms: duration
},
level: response.ok ? 'info' : 'error'
});
return response;
} catch (error) {
Sentry.addBreadcrumb({
type: 'error',
category: 'fetch',
message: `${options.method} ${endpoint} failed`,
data: {
error: String(error)
},
level: 'error'
});
throw error;
}
}
User Journey Tracking
import * as Sentry from '@sentry/node';
class UserJourneyTracker {
trackStep(step: string, metadata?: Record<string, any>) {
Sentry.addBreadcrumb({
type: 'user',
category: 'user.journey',
message: `User completed: ${step}`,
data: {
step,
...metadata
},
level: 'info'
});
}
}
const tracker = new UserJourneyTracker();
// Track user journey
tracker.trackStep('view_product', { productId: '123' });
tracker.trackStep('add_to_cart', { productId: '123', quantity: 2 });
tracker.trackStep('view_cart');
tracker.trackStep('checkout_started');
tracker.trackStep('payment_info_entered');
tracker.trackStep('order_completed', { orderId: '456', amount: 99.99 });
State Change Tracking
import * as Sentry from '@sentry/node';
function trackStateChange<T>(
stateName: string,
oldValue: T,
newValue: T
) {
Sentry.addBreadcrumb({
type: 'default',
category: 'state',
message: `${stateName} changed`,
data: {
state: stateName,
from: oldValue,
to: newValue
},
level: 'debug'
});
}
// Usage
trackStateChange('connectionStatus', 'disconnected', 'connected');
trackStateChange('userRole', 'guest', 'authenticated');
Breadcrumb Limits
By default, Sentry keeps the last 100 breadcrumbs:
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'your-dsn',
maxBreadcrumbs: 50 // Keep only last 50 breadcrumbs
});
Best Practices
1. Use Descriptive Categories
// Bad
Sentry.addBreadcrumb({ message: 'Action' });
// Good
Sentry.addBreadcrumb({
category: 'user.action',
message: 'User clicked submit button'
});
2. Include Relevant Data
Sentry.addBreadcrumb({
category: 'api',
message: 'Fetching user data',
data: {
userId: '123',
endpoint: '/api/users/123',
cacheHit: false
}
});
3. Use Appropriate Levels
// Debug: Development info
Sentry.addBreadcrumb({ message: 'Cache miss', level: 'debug' });
// Info: Normal operations
Sentry.addBreadcrumb({ message: 'User login', level: 'info' });
// Warning: Potential issues
Sentry.addBreadcrumb({ message: 'Retry attempt 3/5', level: 'warning' });
// Error: Error conditions
Sentry.addBreadcrumb({ message: 'API timeout', level: 'error' });
4. Don’t Log Sensitive Data
// Bad
Sentry.addBreadcrumb({
message: 'User login',
data: {
username: '[email protected]',
password: 'secret123' // Never log passwords!
}
});
// Good
Sentry.addBreadcrumb({
message: 'User login',
data: {
username: '[email protected]',
method: 'password'
}
});