Error Reporting (Sentry)
Trezor Suite uses Sentry.io for automated error tracking and performance monitoring, helping the team quickly identify and fix issues across different environments.
Overview
Sentry integration provides:
Error Tracking Automatic capture of unhandled errors
Performance Monitoring Track app performance metrics
Breadcrumbs User actions leading to errors
Context Device, system, and app state information
Sentry only receives data when users have enabled anonymous data collection in Settings.
What Gets Reported
When analytics enabled:
interface SentryError {
// Error details
message : string ;
stack : string ;
type : string ;
// Context
level : 'error' | 'warning' | 'info' ;
timestamp : number ;
// User actions (breadcrumbs)
breadcrumbs : Breadcrumb [];
// System info
context : SentryContext ;
}
Breadcrumbs
User actions before error:
interface Breadcrumb {
// Action type
type : 'navigation' | 'click' | 'network' | 'redux' ;
// Action details
message : string ;
data ?: Record < string , any >;
// Timing
timestamp : number ;
level : 'info' | 'warning' | 'error' ;
}
// Example breadcrumbs:
[
{
type: 'navigation' ,
message: 'Navigated to /accounts/btc' ,
timestamp: 1634644852099 ,
},
{
type: 'redux' ,
message: '@account/update' ,
timestamp: 1634644853131 ,
},
{
type: 'network' ,
message: 'GET /api/rates' ,
data: { status: 200 },
timestamp: 1634644853306 ,
},
{
type: 'error' ,
message: 'TypeError: Cannot read property...' ,
timestamp: 1634644854072 ,
level: 'error' ,
}
]
System Context
Environment information:
interface SentryContext {
// Application
app : {
version : string ;
environment : 'desktop' | 'web' | 'mobile' ;
commitId : string ;
};
// System
os : {
name : string ; // 'Windows', 'macOS', 'Linux'
version : string ; // '10.0.19042'
};
// Browser (web only)
browser ?: {
name : string ; // 'Chrome', 'Firefox'
version : string ; // '96.0.4664.110'
};
// Device (mobile only)
device ?: {
model : string ;
manufacturer : string ;
};
}
Redacted device details:
// Device features (sensitive fields redacted)
const deviceInfo = {
available: boolean ,
connected: boolean ,
features: {
model: 'T' , // T1B1, T2T1, etc.
major_version: 2 ,
minor_version: 4 ,
patch_version: 2 ,
firmware: 'valid' ,
// Capabilities
capabilities: [
'Capability_Bitcoin' ,
'Capability_Ethereum' ,
// ...
],
// Redacted fields
device_id: '[redacted]' ,
label: '[redacted]' ,
session_id: '[redacted]' ,
},
};
Redux State
Limited app state:
// Enabled coins
enabledCoins : [ 'btc' , 'ltc' , 'eth' , 'xrp' , 'doge' ]
// Discovery status
walletDiscovery : [
{
bundleSize: 0 ,
deviceState: '[redacted]' ,
failed: [],
index: 0 ,
loaded: 14 ,
networks: [ 'btc' , 'ltc' , 'eth' , 'xrp' ],
status: 4 ,
total: 14 ,
}
]
// Recent actions (last 20)
actionLog : [
{ time: 1634644852099 , type: '@suite/online-status' },
{ time: 1634644852104 , type: '@suite/init' },
{ time: 1634644852966 , type: '@message-system/save-valid-messages' },
// ...
]
What’s Redacted
Sensitive data removed:
Always redacted:
Device IDs
Device labels
Session IDs
State keys
Addresses
XPUBs
Transaction data
Balances
Private information
Initialization
Sentry setup:
import * as Sentry from '@sentry/electron' ;
import { SENTRY_CONFIG } from '@suite-config' ;
// Initialize on app start
Sentry . init ({
dsn: SENTRY_CONFIG . dsn ,
environment: SENTRY_CONFIG . environment ,
release: `suite@ ${ VERSION } ` ,
// Only if analytics enabled
enabled: analyticsEnabled ,
// Sample rate
tracesSampleRate: 0.1 ,
// Integrations
integrations: [
new Sentry . Integrations . Breadcrumbs ({
console: false , // Don't log console
dom: true , // Track clicks
fetch: true , // Track network
history: true , // Track navigation
}),
],
// Before sending
beforeSend : ( event , hint ) => {
// Redact sensitive data
return redactSensitiveData ( event );
},
});
Error Capture
Automatic Capture
Unhandled errors automatically reported:
// Uncaught exceptions
window . addEventListener ( 'error' , ( event ) => {
Sentry . captureException ( event . error );
});
// Promise rejections
window . addEventListener ( 'unhandledrejection' , ( event ) => {
Sentry . captureException ( event . reason );
});
// React error boundaries
class ErrorBoundary extends React . Component {
componentDidCatch ( error , errorInfo ) {
Sentry . captureException ( error , {
contexts: { react: errorInfo },
});
}
}
Manual Capture
Explicit error reporting:
import * as Sentry from '@sentry/electron' ;
try {
await riskyOperation ();
} catch ( error ) {
// Report with context
Sentry . captureException ( error , {
tags: {
operation: 'blockchain-sync' ,
network: 'btc' ,
},
extra: {
accountIndex: 0 ,
retryCount: 3 ,
},
});
// Handle error
showErrorMessage ( error );
}
Message Capture
Log important events:
// Non-error messages
Sentry . captureMessage ( 'User exceeded rate limit' , {
level: 'warning' ,
tags: {
feature: 'coinjoin' ,
},
});
Breadcrumb Tracking
Custom breadcrumb recording:
import * as Sentry from '@sentry/electron' ;
// Redux actions
store . subscribe (() => {
const action = store . getState (). lastAction ;
Sentry . addBreadcrumb ({
category: 'redux' ,
message: action . type ,
level: 'info' ,
data: sanitizeAction ( action ),
});
});
// User interactions
const handleClick = ( element : string ) => {
Sentry . addBreadcrumb ({
category: 'ui' ,
message: `Clicked ${ element } ` ,
level: 'info' ,
});
};
// Network requests
const fetchData = async ( url : string ) => {
Sentry . addBreadcrumb ({
category: 'http' ,
message: `GET ${ url } ` ,
level: 'info' ,
});
const response = await fetch ( url );
Sentry . addBreadcrumb ({
category: 'http' ,
message: `Response ${ response . status } ` ,
data: { status: response . status },
});
return response ;
};
Track app performance:
Transactions
Measure operations:
// Start transaction
const transaction = Sentry . startTransaction ({
op: 'account.discovery' ,
name: 'Account Discovery' ,
});
try {
// Perform discovery
const accounts = await discoverAccounts ();
transaction . setStatus ( 'ok' );
transaction . setData ( 'accountsFound' , accounts . length );
} catch ( error ) {
transaction . setStatus ( 'error' );
throw error ;
} finally {
transaction . finish ();
}
Spans
Measure sub-operations:
const transaction = Sentry . getCurrentTransaction ();
// Network span
const span = transaction ?. startChild ({
op: 'http' ,
description: 'Fetch blockchain data' ,
});
try {
await fetch ( url );
span ?. setStatus ( 'ok' );
} finally {
span ?. finish ();
}
User Context
Associate errors with users:
// Set user context (anonymized)
Sentry . setUser ({
id: instanceId , // Anonymous instance ID
// Never include:
// - Real names
// - Email addresses
// - Device IDs
});
// Clear on logout/disable
Sentry . setUser ( null );
Tags and Context
Organize errors:
// Set tags for filtering
Sentry . setTag ( 'environment' , 'desktop' );
Sentry . setTag ( 'feature' , 'coinjoin' );
Sentry . setTag ( 'network' , 'btc' );
// Set additional context
Sentry . setContext ( 'device' , {
model: device . features . model ,
firmware: device . firmware ,
});
Sentry . setContext ( 'wallet' , {
enabledCoins: coins ,
accountCount: accounts . length ,
});
Privacy Protection
Data Scrubbing
Automatic PII removal:
const beforeSend = ( event : SentryEvent ) : SentryEvent | null => {
// Redact sensitive patterns
event = redactPatterns ( event , [
/xpub [ a-zA-Z0-9 ] + / gi , // XPUBs
/ [ 13 ][ a-km-zA-HJ-NP-Z1-9 ] {25,34} / gi , // Bitcoin addresses
/0x [ a-fA-F0-9 ] {40} / gi , // Ethereum addresses
]);
// Remove sensitive fields
if ( event . extra ) {
delete event . extra . privateKey ;
delete event . extra . mnemonic ;
delete event . extra . xpriv ;
}
return event ;
};
IP Address Handling
Rare exception: In rare cases before Suite loads its storage, an error might be sent before Suite knows if analytics are enabled. However, no private data can be sent since storage isn’t loaded yet.
Consent Management
Respect user preferences:
// Enable/disable based on consent
const updateSentryConsent = ( enabled : boolean ) => {
const client = Sentry . getCurrentHub (). getClient ();
if ( enabled ) {
client ?. getOptions (). enabled = true ;
} else {
client ?. getOptions (). enabled = false ;
// Clear any queued events
client ?. close ();
}
};
// React to consent changes
store . subscribe (() => {
const consent = store . getState (). analytics . enabled ;
updateSentryConsent ( consent );
});
Error Grouping
Sentry groups similar errors:
// Custom fingerprinting
Sentry . configureScope ( scope => {
scope . setFingerprint ([
'{{ default }}' ,
errorType ,
componentName ,
]);
});
// Group by error type + location
// Instead of by message (which varies)
Release Tracking
Track errors by version:
Sentry . init ({
release: `suite@ ${ VERSION } ` , // e.g., "[email protected] "
// Source maps for stack traces
integrations: [
new Sentry . Integrations . RewriteFrames ({
iteratee : ( frame ) => {
frame . filename = frame . filename . replace (
'app:///' ,
'~/'
);
return frame ;
},
}),
],
});
Testing
Test Error Capture
// Trigger test error
Sentry . captureException ( new Error ( 'Test error' ));
// Verify in Sentry dashboard
// Should appear within seconds
Local Development
// Disable in development
Sentry . init ({
enabled: process . env . NODE_ENV === 'production' ,
// OR
enabled: false , // Always disabled locally
});
Dashboard & Monitoring
Sentry dashboard provides:
Issues
Performance
Releases
Alerts
Grouped errors
Frequency graphs
Affected users
Release tracking
Transaction durations
Slow operations
Performance trends
Bottleneck identification
Version tracking
New issues per release
Regression detection
Adoption rates
Spike notifications
New issue alerts
Performance degradation
Error rate thresholds
Best Practices
Enable analytics to help fix bugs
No sensitive data is sent
Can disable anytime
Use Tor for extra privacy
Never log sensitive data
Add context to errors
Use breadcrumbs effectively
Test error reporting
Monitor Sentry dashboard
Triage issues promptly
Common Issues
Problem: Sentry quota exceededSolution:
Increase sample rate filtering
Ignore noisy errors
Use before-send filtering
Upgrade Sentry plan
Problem: Errors lack useful contextSolution:
Add more breadcrumbs
Set appropriate tags
Include relevant extra data
Improve error messages
Problem: Sensitive data in SentrySolution:
Update beforeSend filter
Add redaction patterns
Review reported data
Use data scrubbing rules
Implementation Files
// Sentry integration
suite - common / sentry /
src /
init . ts // Sentry initialization
redaction . ts // Data scrubbing
breadcrumbs . ts // Breadcrumb tracking
// Configuration
suite - common / suite - config /
src /
sentry . ts // Sentry config
// Platform-specific
packages / suite - desktop /
src /
sentry . ts // Desktop Sentry setup
packages / suite - web /
src /
sentry . ts // Web Sentry setup
suite - native /
src /
sentry . ts // Mobile Sentry setup