๐Ÿš€ App Publishing, Monetization, and Product Development

Analytics and Crash Reporting for Android Apps

Without analytics you don't know whether users reach your key feature. Without crash reporting you only learn about crashes from one-star reviews. Here's how to instrument an Android app so you get actionable data, while respecting privacy.

โœ๏ธ Yunok Tech ๐Ÿ“… Updated โฑ 3 min read ๐ŸŽฏ Intermediate
On this page
  1. The observability stack
  2. Designing analytics events
  3. Crash reporting that helps you fix things
  4. Privacy and consent
  5. From data to decisions
  6. Frequently asked questions
  7. Conclusion

Many apps track either everything (thousands of meaningless events) or nothing. Good instrumentation starts from questions: where do new users drop off, which features drive retention, which crashes affect most users, and adds just enough events to answer them.

The observability stack

Analytics and crash reporting stack The app sends product analytics events for funnels and retention, crash and non-fatal reports with breadcrumbs and custom keys, and performance traces. Play Console Android vitals adds system-level crash, ANR and performance data. Together they inform product and engineering decisions. App Analytics: funnels, retention Crash + non-fatal reports Performance traces + Android vitals (Play)
Product analytics answer "what do users do?". Crash and vitals data answer "what breaks?".

Designing analytics events

  1. Write the questions first: "What % of new users create their first note within a day?"
  2. Define a small event set: verbs in snake_case, with consistent parameters.
  3. Document it in a tracking plan, and review new events in PRs.
A typed analytics wrapperKotlin
sealed class AnalyticsEvent(val name: String, val params: Map<String, Any> = emptyMap()) {
    data object SignUpCompleted : AnalyticsEvent("sign_up_completed")
    data class NoteCreated(val source: String) : AnalyticsEvent("note_created", mapOf("source" to source))
    data class PaywallViewed(val placement: String) : AnalyticsEvent("paywall_viewed", mapOf("placement" to placement))
    data class PurchaseCompleted(val productId: String) : AnalyticsEvent("purchase_completed", mapOf("product_id" to productId))
}

interface Analytics { fun log(event: AnalyticsEvent) }

class FirebaseAnalyticsLogger(private val fa: FirebaseAnalytics) : Analytics {
    override fun log(event: AnalyticsEvent) {
        fa.logEvent(event.name, Bundle().apply {
            event.params.forEach { (k, v) ->
                when (v) {
                    is String -> putString(k, v)
                    is Long -> putLong(k, v)
                    is Int -> putLong(k, v.toLong())
                    is Double -> putDouble(k, v)
                }
            }
        })
    }
}

A typed wrapper prevents typos, makes events searchable in code, and lets you swap providers, or use a no-op in tests and debug builds.

Crash reporting that helps you fix things

Context for crash reportsKotlin
// Custom keys and breadcrumbs make crashes reproducible (never include personal data)
Firebase.crashlytics.setCustomKeys {
    key("feature_flag_new_checkout", flags.isEnabled(Flag.NEW_CHECKOUT))
    key("current_screen", "Checkout")
}
Firebase.crashlytics.log("Tapped Pay with UPI")      // breadcrumb

// Non-fatal: important failures that didn't crash
try {
    paymentRepository.confirm(orderId)
} catch (e: PaymentException) {
    Firebase.crashlytics.recordException(e)
    showPaymentError()
}
  • Upload R8 mapping files so stack traces are readable. The Crashlytics Gradle plugin can do this.
  • Triage by users affected and trend after release, not just event counts.
  • Use Android Studio's App Quality Insights to jump from crash clusters to source.

Privacy and consent

  • Never log personal data (names, emails, phone numbers, message content) in events or crash logs.
  • Respect consent requirements in your markets, and provide an opt-out (for example setAnalyticsCollectionEnabled(false)).
  • Disclose analytics and crash SDKs in the Play Data safety form and privacy policy.
  • Disable collection in debug builds to keep data clean.

From data to decisions

Onboarding drop-off

The funnel shows 40% drop at a permission screen. Move the permission request into context, then measure again.

Crash after release

A new cluster on one Android version. Halt the staged rollout, fix it, and resume.

Feature value

Users who use search in week 1 retain better. Make search more discoverable.

Frequently asked questions

How many events should I track?

Usually a few dozen well-defined events are enough. Each event should answer a question someone will actually ask.

Crashlytics or Android vitals?

Both. Vitals shows system-level data for all Play users, including ANRs. Crashlytics adds custom context, non-fatals and faster iteration.

Can analytics slow my app?

SDK initialisation and heavy logging can affect startup. Initialise lazily where possible, and measure.

Conclusion

Instrument with intent: a small, documented event set for product questions, crash reporting with context and non-fatals for engineering, Android vitals for system health, and privacy by design throughout.

Next step: launch your own product with Building and Launching an Android App as a Solo Developer.

Official references

๐Ÿ“ฑ Apps built by Yunok Tech

Real Android apps on Google Play, free to download.

See all our apps โ†’

Ready to build real Android applications?

Shipping is a skill of its own. Learn to take an app from a working build to a polished, signed release that real users can install from Google Play.

Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.

Explore the Android course and take your next step as an Android developer.

Share: LinkedIn X / Twitter WhatsApp