{"slug":"firebase-crashlytics","title":"firebase-crashlytics","summary":"Use when implementing crash reporting, capturing fatal/non-fatal errors, recording isolate/async exceptions, customizing reports, or uploading obfuscated symbols.","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-30T09:57:17.655585Z","repo":{"url":"https://github.com/evanca/flutter-ai-rules","stars":644,"forks":67,"license":"MIT","updatedAt":"2026-09-14T07:51:38Z"},"bodyHtml":"<hr>\n<h2>name: firebase-crashlytics\ndescription: \"Use when implementing crash reporting, capturing fatal/non-fatal errors, recording isolate/async exceptions, customizing reports, or uploading obfuscated symbols.\"\nlicense: MIT</h2>\n<h1>Firebase Crashlytics Skill</h1>\n<p>This skill defines how to correctly use Firebase Crashlytics in Flutter applications.</p>\n<h2>When to Use</h2>\n<p>Use this skill when:</p>\n<ul>\n<li>Implementing crash reporting in a Flutter project.</li>\n<li>Capturing fatal errors, non-fatal exceptions, and async/isolate errors.</li>\n<li>Customizing crash reports with keys, logs, and user identifiers.</li>\n<li>Configuring opt-in data collection or disabling reporting in debug builds.</li>\n<li>Uploading symbol files for obfuscated builds.</li>\n</ul>\n<hr>\n<h2>1. Setup and Configuration</h2>\n<pre><code>flutter pub add firebase_crashlytics\nflutter pub add firebase_analytics  # enables breadcrumb logs for better crash context\n</code></pre>\n<p>Run <code>flutterfire configure</code> to update the Firebase configuration and add the required Crashlytics Gradle plugin for Android.</p>\n<pre><code>import 'package:firebase_crashlytics/firebase_crashlytics.dart';\n</code></pre>\n<p><strong>Obfuscated code:</strong></p>\n<ul>\n<li>For apps built with <code>--split-debug-info</code> and/or <code>--obfuscate</code>, upload symbol files for readable stack traces.</li>\n<li><strong>iOS:</strong> Flutter 3.12.0+ and Crashlytics Flutter plugin 3.3.4+ handle symbol upload automatically.</li>\n<li><strong>Android:</strong> Use Firebase CLI (v11.9.0+) to upload Flutter debug symbols:</li>\n</ul>\n<pre><code>firebase crashlytics:symbols:upload --app=FIREBASE_APP_ID PATH/TO/symbols\n</code></pre>\n<hr>\n<h2>2. Error Handling</h2>\n<p>Configure comprehensive error capture in <code>main()</code> to catch errors from all sources:</p>\n<p><strong>Fatal Flutter errors:</strong></p>\n<pre><code>void main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await Firebase.initializeApp();\n\n  // Pass all uncaught fatal errors from the framework to Crashlytics\n  FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;\n\n  // Catch async errors not handled by the Flutter framework\n  PlatformDispatcher.instance.onError = (error, stack) {\n    FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);\n    return true;\n  };\n\n  runApp(MyApp());\n}\n</code></pre>\n<p><strong>Non-fatal Flutter errors:</strong> use <code>recordFlutterError</code> instead of <code>recordFlutterFatalError</code>.</p>\n<p><strong>Isolate errors:</strong></p>\n<pre><code>Isolate.current.addErrorListener(RawReceivePort((pair) async {\n  final List&lt;dynamic&gt; errorAndStacktrace = pair;\n  await FirebaseCrashlytics.instance.recordError(\n    errorAndStacktrace.first,\n    errorAndStacktrace.last,\n    fatal: true,\n  );\n}).sendPort);\n</code></pre>\n<p><strong>Caught exceptions (non-fatal):</strong></p>\n<pre><code>await FirebaseCrashlytics.instance.recordError(\n  error,\n  stackTrace,\n  reason: 'a non-fatal error',\n  information: ['further diagnostic information about the error', 'version 2.0'],\n);\n</code></pre>\n<ul>\n<li>Crashlytics only stores the <strong>most recent 8 non-fatal exceptions</strong> per session — older ones are discarded.</li>\n</ul>\n<hr>\n<h2>3. Crash Report Customization</h2>\n<p><strong>Custom keys</strong> (max 64 key/value pairs, up to 1 kB each):</p>\n<pre><code>FirebaseCrashlytics.instance.setCustomKey('str_key', 'hello');\nFirebaseCrashlytics.instance.setCustomKey('bool_key', true);\nFirebaseCrashlytics.instance.setCustomKey('int_key', 1);\n</code></pre>\n<p><strong>Custom log messages</strong> (limit: 64 kB per session):</p>\n<pre><code>FirebaseCrashlytics.instance.log(\"User tapped on payment button\");\n</code></pre>\n<p><strong>User identifier:</strong></p>\n<pre><code>FirebaseCrashlytics.instance.setUserIdentifier(\"user-123\");\n// Clear by setting to blank string\nFirebaseCrashlytics.instance.setUserIdentifier(\"\");\n</code></pre>\n<ul>\n<li>Avoid putting unique values (user IDs, timestamps) directly in exception messages — use custom keys instead.</li>\n</ul>\n<hr>\n<h2>4. Performance and Optimization</h2>\n<ul>\n<li>Crashlytics processes exceptions on a <strong>dedicated background thread</strong> to minimize performance impact.</li>\n<li><strong>Fatal</strong> reports are sent in real-time without requiring an app restart.</li>\n<li><strong>Non-fatal</strong> reports are written to disk and sent with the next fatal report or on app restart.</li>\n<li>Use breadcrumb logs (requires Firebase Analytics) to understand user actions leading up to a crash.</li>\n</ul>\n<p><strong>Disable Crashlytics in debug builds:</strong></p>\n<pre><code>if (kReleaseMode) {\n  await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);\n} else {\n  await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(false);\n}\n</code></pre>\n<hr>\n<h2>5. Testing and Debugging</h2>\n<p>Force a test crash to verify the setup:</p>\n<pre><code>FirebaseCrashlytics.instance.crash();\n</code></pre>\n<p><strong>Verification workflow:</strong></p>\n<ol>\n<li>Build and run the app in release mode.</li>\n<li>Trigger the test crash.</li>\n<li>Reopen the app so the crash report is uploaded.</li>\n<li>Check the Firebase Console Crashlytics dashboard within 5 minutes.</li>\n<li>Verify that custom keys, logs, and user identifiers appear on the crash report.</li>\n</ol>\n<ul>\n<li>Verify stack traces are properly symbolicated when using code obfuscation.</li>\n</ul>\n<hr>\n<h2>6. Opt-in Reporting</h2>\n<p>By default, Crashlytics automatically collects crash reports for all users.</p>\n<p>To give users control over data collection:</p>\n<ul>\n<li>Disable automatic reporting and enable it only via <code>setCrashlyticsCollectionEnabled(true)</code> when users opt in.</li>\n<li>The override value <strong>persists</strong> across all subsequent app launches.</li>\n<li>To opt a user out, pass <code>false</code> — this applies from the next app launch.</li>\n<li>When disabled, crash info is <strong>stored locally</strong>; if later enabled, locally stored crashes are sent to Crashlytics.</li>\n</ul>\n<hr>\n<h2>References</h2>\n<ul>\n<li><a href=\"https://firebase.google.com/docs/crashlytics/get-started?platform=flutter\">Firebase Crashlytics Flutter documentation</a></li>\n<li><a href=\"https://firebase.google.com/docs/crashlytics/customize-crash-reports?platform=flutter\">Customize crash reports</a></li>\n</ul>\n","files":[{"path":"SKILL.md","sizeBytes":5517,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-08-30T09:58:19.44967Z","sha256":"7BA8545FF9E7D1ECC2AC893D0C7E8552B3AE3E328F353823C077AFAD4B094D79","sizeBytes":2351},"review":null,"source":{"repositoryUrl":"https://github.com/evanca/flutter-ai-rules","path":"skills/firebase-crashlytics","license":"MIT","commit":"7b9cce235714ae17acbae896b1e8c8627e128f4c","subtreeSha":"8CF4F8B2F9CB859376446E5C796D75B7689C585258AF615AC2EDD9B06B5DE573","lastSyncedAt":"2026-09-29T23:32:26.661053Z"},"reviewedAt":"2026-08-30T10:14:03.441037Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/evanca/flutter-ai-rules/tree/main/skills/firebase-crashlytics"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install evanca-flutter-ai-rules@llmmart"},{"target":"git","command":"git clone https://github.com/evanca/flutter-ai-rules.git"}]}