Implementing Breadcrumbs (Action Trail Before Crash) in Mobile Apps
A crash without context is a line in a stack trace and the question "how do I reproduce this?" Breadcrumbs are a chronological log of events preceding a crash: screen transitions, button taps, HTTP requests, custom events. The difference between "NullPointerException in ProductViewModel" and the same crash with breadcrumbs is the difference between an hour of debugging and two minutes to fix.
How Sentry Stores Breadcrumbs
The Sentry SDK keeps a circular buffer of breadcrumbs in memory. By default — the last 100 events. On crash, the buffer is serialized and sent with the crash report. The buffer is not written to disk between sessions — only for the current app run.
Important: if the app closed cleanly (backgrounded) and the crash occurred on next launch — the previous session's breadcrumbs are unavailable.
Automatic Breadcrumbs
Sentry adds some breadcrumbs automatically:
iOS:
SentrySDK.start { options in
options.dsn = "https://[email protected]/project"
options.enableAutoBreadcrumbTracking = true
// Automatically: UIViewController transitions, HTTP requests (URLSession),
// System notifications (UIApplicationDidBecomeActiveNotification, etc.)
}
Android:
SentryAndroid.init(this) { options ->
options.dsn = "https://[email protected]/project"
options.isEnableActivityLifecycleBreadcrumbs = true // Activity transitions
options.isEnableUserInteractionBreadcrumbs = true // Click events
options.isEnableNetworkEventBreadcrumbs = true // Network requests
options.isEnableAppComponentBreadcrumbs = true // App lifecycle
}
Automatic breadcrumbs cover navigation and networking. Everything above framework level — add manually.
Custom Breadcrumbs
// iOS — navigation event in custom router
SentrySDK.addBreadcrumb({
let crumb = Breadcrumb()
crumb.category = "navigation"
crumb.message = "Opened ProductDetail"
crumb.data = ["product_id": productId, "source": "search"]
crumb.level = .info
return crumb
}())
// Android — business event
val breadcrumb = Breadcrumb().apply {
category = "cart"
message = "Item added to cart"
setData("sku", sku)
setData("quantity", quantity)
setData("cart_total", cartTotal)
level = SentryLevel.INFO
}
Sentry.addBreadcrumb(breadcrumb)
Structuring Breadcrumbs for Diagnostics
Breadcrumb categories determine their display in the Sentry UI. Common categories:
| Category | Purpose |
|---|---|
navigation |
Screen transitions |
ui.click |
Button taps, list items |
http |
Network requests (automatic) |
auth |
Authorization, user change |
cart |
Cart, checkout |
lifecycle |
Background/active mode |
Specific data in data is key to quick diagnostics:
// Good: you see exactly what happened
breadcrumb.setData("screen", "CheckoutStep3")
breadcrumb.setData("payment_method", "card")
breadcrumb.setData("card_type", "visa")
// Bad: unclear without source code
breadcrumb.setData("step", 3)
breadcrumb.setData("type", "card")
Buffer Configuration
// iOS — increase breadcrumbs limit
SentrySDK.start { options in
options.maxBreadcrumbs = 200 // default 100
}
200 events for an active user is about 2–3 minutes of interaction. For complex flows (signup, payment), this is enough. More isn't needed: crash reports become too large and old events are useless.
Navigation Framework Integration
React Native Navigation:
// React Navigation v6 — automatic breadcrumbs on transitions
import * as Sentry from "@sentry/react-native";
import { useNavigationContainerRef } from "@react-navigation/native";
const navigationRef = useNavigationContainerRef();
function App() {
return (
<NavigationContainer
ref={navigationRef}
onStateChange={() => {
const currentRoute = navigationRef.getCurrentRoute();
Sentry.addBreadcrumb({
category: "navigation",
message: `Navigated to ${currentRoute?.name}`,
level: "info",
});
}}
>
Flutter:
// NavigatorObserver for automatic breadcrumbs
class SentryNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route route, Route? previousRoute) {
Sentry.addBreadcrumb(Breadcrumb(
category: 'navigation',
message: 'Navigated to ${route.settings.name}',
level: SentryLevel.info,
));
}
}
// In MaterialApp:
navigatorObservers: [SentryNavigatorObserver()],
Protection Against Data Leaks
Breadcrumbs can contain sensitive data. Configure a before-send filter:
options.beforeBreadcrumb = { breadcrumb in
// Don't log breadcrumbs with tokens and passwords
if breadcrumb.category == "http",
let url = breadcrumb.data?["url"] as? String,
url.contains("/auth") || url.contains("/payment") {
return nil // don't add this breadcrumb
}
return breadcrumb
}
What We Do
- Enable automatic breadcrumbs for navigation, networking, and lifecycle
- Define taxonomy of custom categories for your business logic
- Add custom breadcrumbs at key points: cart, payment, authorization
- Integrate with navigation frameworks (React Navigation, Flutter Navigator)
- Configure
beforeBreadcrumbfilter to exclude sensitive data
Timeline
Basic setup with automatic breadcrumbs: 4–8 hours. Full instrumentation with custom categories: 2–3 days. Pricing is calculated individually.







