Breadcrumbs
Track the sequence of user actions and events that lead to errors.
Overview
Breadcrumbs are a trail of events that happened before an error occurred. They help you understand the user journey and reproduce issues.
User Journey:
├── [navigation] Loaded /dashboard
├── [ui] Clicked "Settings" button
├── [http] GET /api/user/settings (200)
├── [ui] Toggled "Dark Mode" switch
├── [http] POST /api/user/settings (500) ← API failed
└── [error] TypeError: Cannot read 'theme' of undefined
Breadcrumb Structure
interface Breadcrumb {
type?: 'default' | 'http' | 'navigation' | 'ui' | 'user' | 'console';
category?: string; // Subcategory (e.g., 'fetch', 'xhr', 'click')
message?: string; // Human-readable description
data?: Record<string, unknown>; // Additional data
level?: 'fatal' | 'error' | 'warning' | 'info' | 'debug';
timestamp?: string; // ISO timestamp
}Breadcrumb Types
| Type | Description | Examples |
|---|---|---|
default | General events | Custom application events |
http | Network requests | API calls, fetch, XHR |
navigation | Page navigation | Route changes, page loads |
ui | User interactions | Clicks, form inputs |
user | User actions | Login, signup, custom actions |
console | Console output | console.log, console.error |
Automatic Breadcrumbs
The SDK captures breadcrumbs automatically:
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
breadcrumbs: {
// Capture console.log/warn/error (default: true)
console: true,
// Capture DOM clicks (default: true)
dom: true,
// Capture fetch/XHR requests (default: true)
fetch: true,
xhr: true,
// Capture history/location changes (default: true)
history: true,
},
});HTTP Breadcrumbs
Automatically captured for fetch and XHR:
// Captured automatically:
{
type: 'http',
category: 'fetch',
message: 'GET /api/users',
data: {
method: 'GET',
url: '/api/users',
statusCode: 200,
duration: 145,
},
level: 'info',
timestamp: '2024-01-15T10:30:00.000Z',
}Navigation Breadcrumbs
Captured on route changes:
// Captured automatically:
{
type: 'navigation',
category: 'navigation',
message: 'Navigation to /dashboard/settings',
data: {
from: '/dashboard',
to: '/dashboard/settings',
},
level: 'info',
timestamp: '2024-01-15T10:30:01.000Z',
}UI Breadcrumbs
Captured on DOM interactions:
// Captured automatically:
{
type: 'ui',
category: 'ui.click',
message: 'button.submit-btn',
data: {
target: 'button.submit-btn',
text: 'Submit',
},
level: 'info',
timestamp: '2024-01-15T10:30:02.000Z',
}Console Breadcrumbs
Captured from console methods:
console.log('User selected plan:', selectedPlan);
// Captured automatically:
{
type: 'console',
category: 'console',
message: "User selected plan: pro",
level: 'info',
timestamp: '2024-01-15T10:30:03.000Z',
}Manual Breadcrumbs
Add custom breadcrumbs for important application events:
addBreadcrumb()
import { getObservability } from '@transactional/observability';
const obs = getObservability();
// Simple breadcrumb
obs.addBreadcrumb({
message: 'User started checkout flow',
category: 'checkout',
});
// Full breadcrumb with all options
obs.addBreadcrumb({
type: 'user',
category: 'checkout',
message: 'User added item to cart',
level: 'info',
data: {
productId: 'prod-123',
productName: 'Widget Pro',
quantity: 2,
price: 29.99,
},
});Common Use Cases
User Authentication
function onLogin(user: User) {
obs.addBreadcrumb({
type: 'user',
category: 'auth',
message: 'User logged in',
level: 'info',
data: {
userId: user.id,
method: 'email',
},
});
}
function onLogout() {
obs.addBreadcrumb({
type: 'user',
category: 'auth',
message: 'User logged out',
level: 'info',
});
}E-commerce Flow
function addToCart(product: Product) {
obs.addBreadcrumb({
type: 'user',
category: 'cart',
message: `Added ${product.name} to cart`,
data: {
productId: product.id,
price: product.price,
},
});
}
function startCheckout(cart: Cart) {
obs.addBreadcrumb({
type: 'user',
category: 'checkout',
message: 'Started checkout',
data: {
itemCount: cart.items.length,
total: cart.total,
},
});
}
function completePayment(orderId: string) {
obs.addBreadcrumb({
type: 'user',
category: 'checkout',
message: 'Payment completed',
data: { orderId },
});
}Feature Usage
function onFeatureEnabled(feature: string) {
obs.addBreadcrumb({
type: 'user',
category: 'feature',
message: `Enabled feature: ${feature}`,
data: { feature },
});
}
function onSettingChanged(setting: string, value: unknown) {
obs.addBreadcrumb({
type: 'user',
category: 'settings',
message: `Changed ${setting}`,
data: { setting, value },
});
}Form Interactions
function onFormStep(step: number, totalSteps: number) {
obs.addBreadcrumb({
type: 'ui',
category: 'form',
message: `Form step ${step}/${totalSteps}`,
data: { step, totalSteps },
});
}
function onFormValidationError(field: string, error: string) {
obs.addBreadcrumb({
type: 'ui',
category: 'form.validation',
message: `Validation error on ${field}`,
level: 'warning',
data: { field, error },
});
}Breadcrumb Limits
To prevent excessive data, breadcrumbs have limits:
| Setting | Default | Max |
|---|---|---|
| Max breadcrumbs per event | 100 | 250 |
| Max message length | 1000 | 2000 |
| Max data size | 4KB | 16KB |
Configuring Limits
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
breadcrumbs: {
maxBreadcrumbs: 150,
maxMessageLength: 1500,
},
});When the limit is reached, oldest breadcrumbs are removed.
Filtering Breadcrumbs
Before Breadcrumb Hook
Filter or modify breadcrumbs before they're recorded:
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
beforeBreadcrumb: (breadcrumb) => {
// Don't record console.debug breadcrumbs
if (breadcrumb.category === 'console' && breadcrumb.level === 'debug') {
return null;
}
// Scrub sensitive data from URLs
if (breadcrumb.type === 'http' && breadcrumb.data?.url) {
breadcrumb.data.url = scrubSensitiveParams(breadcrumb.data.url);
}
// Don't record health check requests
if (breadcrumb.data?.url?.includes('/health')) {
return null;
}
return breadcrumb;
},
});Disabling Specific Types
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
breadcrumbs: {
console: false, // Disable console breadcrumbs
dom: true,
fetch: true,
xhr: true,
history: true,
},
});Sensitive Data
Be careful not to include sensitive data in breadcrumbs:
// Bad - includes password
obs.addBreadcrumb({
message: 'Login attempt',
data: {
email: user.email,
password: user.password, // Don't do this!
},
});
// Good - sanitized
obs.addBreadcrumb({
message: 'Login attempt',
data: {
email: user.email,
// Password omitted
},
});Automatic Scrubbing
The SDK automatically scrubs common sensitive fields:
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
// Fields to automatically scrub (default list)
sensitiveFields: [
'password',
'secret',
'token',
'apiKey',
'api_key',
'authorization',
'creditCard',
'credit_card',
'ssn',
],
});Viewing Breadcrumbs
In the Dashboard
- Go to Issues and click an issue
- Click the Breadcrumbs tab
- View the timeline of events before the error
Timeline View
Timeline:
10:30:00.000 [navigation] Loaded /checkout
10:30:01.234 [http] GET /api/cart (200)
10:30:02.456 [ui] Clicked "Apply Coupon"
10:30:03.789 [http] POST /api/coupon/validate (400)
10:30:04.012 [ui] Clicked "Complete Purchase"
10:30:04.567 [http] POST /api/checkout (500) ← Error
10:30:04.890 [error] PaymentError: Card declined
Filtering
Filter breadcrumbs by:
- Type (http, navigation, ui, etc.)
- Level (error, warning, info)
- Category
- Time range
Best Practices
1. Add Breadcrumbs at Key Points
// User journey milestones
obs.addBreadcrumb({ message: 'Signed up' });
obs.addBreadcrumb({ message: 'Completed onboarding' });
obs.addBreadcrumb({ message: 'First purchase' });2. Include Relevant Data
// Include data that helps debugging
obs.addBreadcrumb({
message: 'Search performed',
data: {
query: searchQuery,
resultsCount: results.length,
filters: activeFilters,
},
});3. Use Appropriate Levels
// Info for normal events
obs.addBreadcrumb({ message: 'Page loaded', level: 'info' });
// Warning for potential issues
obs.addBreadcrumb({ message: 'Retry attempt 2/3', level: 'warning' });
// Error for failures (before the main error)
obs.addBreadcrumb({ message: 'API call failed', level: 'error' });4. Be Consistent with Categories
// Use consistent category naming
const CATEGORIES = {
AUTH: 'auth',
CART: 'cart',
CHECKOUT: 'checkout',
NAVIGATION: 'navigation',
API: 'api',
};
obs.addBreadcrumb({
category: CATEGORIES.AUTH,
message: 'Login successful',
});Next Steps
- Context - Add user and request context
- Alerts - Configure error notifications
- Stack Traces - Configure stack trace capture
On This Page
- Overview
- Breadcrumb Structure
- Breadcrumb Types
- Automatic Breadcrumbs
- HTTP Breadcrumbs
- Navigation Breadcrumbs
- UI Breadcrumbs
- Console Breadcrumbs
- Manual Breadcrumbs
- addBreadcrumb()
- Common Use Cases
- User Authentication
- E-commerce Flow
- Feature Usage
- Form Interactions
- Breadcrumb Limits
- Configuring Limits
- Filtering Breadcrumbs
- Before Breadcrumb Hook
- Disabling Specific Types
- Sensitive Data
- Automatic Scrubbing
- Viewing Breadcrumbs
- In the Dashboard
- Timeline View
- Filtering
- Best Practices
- 1. Add Breadcrumbs at Key Points
- 2. Include Relevant Data
- 3. Use Appropriate Levels
- 4. Be Consistent with Categories
- Next Steps