| name | sentry-mobile |
| description | Set up Sentry on mobile with error reporting, performance tracing, and session replay. Includes the iOS/Android/Flutter/RN SDKs and the privacy and cost caveats of session replay on mobile. |
Sentry for Mobile
Instructions
Sentry is a unified error + performance + replay tool. On mobile it covers native crashes, ANRs, non-fatals, transactions, and (as of 2024+) session replay. This skill sets up Sentry safely and cost-consciously.
1. Project Layout
- Create one Sentry project per platform (
my-app-ios, my-app-android, my-app-flutter) so release health dashboards stay clean.
- Create a release naming scheme:
my-app@<semver>+<build> e.g. my-app@4.12.0+4120. Use the same scheme in every SDK.
- Configure an auth token for CI with scopes
project:read, project:releases, org:read.
2. Android (Kotlin)
plugins {
id("io.sentry.android.gradle") version "4.14.1"
}
sentry {
autoUploadProguardMapping.set(true)
uploadNativeSymbols.set(true)
includeNativeSources.set(false)
tracingInstrumentation {
enabled.set(true)
}
}
class App : Application() {
override fun onCreate() {
super.onCreate()
SentryAndroid.init(this) { options ->
options.dsn = BuildConfig.SENTRY_DSN
options.environment = BuildConfig.BUILD_TYPE
options.release = "my-app@${BuildConfig.VERSION_NAME}+${BuildConfig.VERSION_CODE}"
options.tracesSampleRate = if (BuildConfig.DEBUG) 1.0 else 0.15
options.isEnableAutoSessionTracking = true
options.isAttachScreenshot = false
options.isAttachViewHierarchy = false
options.beforeSend = SentryOptions.BeforeSendCallback { event, _ ->
redact(event)
}
}
}
}
3. iOS (Swift)
Add via SPM (https://github.com/getsentry/sentry-cocoa) and upload dSYMs in a Run Script phase:
SENTRY_CLI="${SRCROOT}/sentry-cli"
"$SENTRY_CLI" debug-files upload --include-sources --auth-token "$SENTRY_AUTH_TOKEN" \
--org my-org --project my-app-ios "$DWARF_DSYM_FOLDER_PATH"
import Sentry
SentrySDK.start { options in
options.dsn = Bundle.main.infoDictionary?["SENTRY_DSN"] as? String
options.environment = Bundle.main.object(forInfoDictionaryKey: "ENVIRONMENT") as? String ?? "release"
options.releaseName = "my-app@\(appVersion)+\(buildNumber)"
options.tracesSampleRate = 0.15
options.enableAppHangTracking = true
options.enableAutoPerformanceTracing = true
options.attachScreenshot = false
options.attachViewHierarchy = false
options.beforeSend = { event in redact(event) }
}
4. Flutter
dependencies:
sentry_flutter: ^8.10.1
Future<void> main() async {
await SentryFlutter.init(
(o) {
o.dsn = const String.fromEnvironment('SENTRY_DSN');
o.environment = const String.fromEnvironment('ENV', defaultValue: 'release');
o.release = 'my-app@${packageInfo.version}+${packageInfo.buildNumber}';
o.tracesSampleRate = kReleaseMode ? 0.15 : 1.0;
o.attachScreenshot = false;
o.beforeSend = (event, hint) async => redact(event);
},
appRunner: () => runApp(const MyApp()),
);
}
Upload Dart debug symbols via sentry-cli dart-symbols upload after flutter build --obfuscate --split-debug-info=build/symbols.
5. React Native
yarn add @sentry/react-native
npx @sentry/wizard@latest -i reactNative
import * as Sentry from '@sentry/react-native';
Sentry.init({
dsn: Config.SENTRY_DSN,
environment: Config.ENV,
release: `my-app@${pkg.version}+${buildNumber}`,
tracesSampleRate: __DEV__ ? 1.0 : 0.15,
enableAutoPerformanceTracing: true,
enableNative: true,
beforeSend: redact,
attachScreenshot: false,
});
6. Performance Tracing
- Sentry auto-instruments app start, navigation, HTTP (OkHttp/URLSession/fetch), and SQLite on all four platforms.
- Use
Sentry.startTransaction for domain-critical flows (checkout, sign-in) so they show up as top-level transactions rather than inside auto-generated parents.
- Keep
tracesSampleRate between 0.10 and 0.20 in production. Use tracesSampler to sample 100% of transactions that contain an error, 1% of noisy background transactions.
7. Session Replay on Mobile -- Caveats
Mobile session replay is not a browser recorder; it reconstructs the UI hierarchy frame-by-frame at a throttled rate. Before enabling it:
- Privacy: mask every
TextView / UILabel / Text by default. Sentry masks by default; verify masking on text, images, webviews, and map views. Explicitly mark anything showing PII with SentryPrivacy.mask(view) (Android) or sentry.mask() modifier (SwiftUI).
- Consent: do not start replay before the user has accepted analytics consent (ATT on iOS, GDPR/DMA consent on EU Android/RN).
- Cost: replay ingest is priced per replay; cap
replaysSessionSampleRate to 0.01-0.05 and set replaysOnErrorSampleRate to 0.5-1.0 so you only pay for sessions that contain errors.
- Webviews (RN / hybrid): replay cannot reliably capture webview content; treat it as masked by default and instrument inside the webview separately.
- Background / PiP: replay pauses in background but the SDK keeps a ring buffer; validate battery impact on low-end devices.
options.sessionReplay.onErrorSampleRate = 1.0
options.sessionReplay.sessionSampleRate = 0.02
options.sessionReplay.maskAllText = true
options.sessionReplay.maskAllImages = true
8. Dashboards and Alerts
- Pin Release Health dashboard per platform: crash-free users, crash-free sessions, adoption.
- Create a regression alert: crash-free users drops by 0.5% across two consecutive releases.
- Create a performance alert: p75 cold start transaction increases by 25% vs baseline.
- Wire alerts to PagerDuty / Slack with the Sentry issue URL in the message (see
on-call-mobile).
Checklist