Android Vitals for Indie Flutter Apps: Crash 1.09% and ANR 0.47% Thresholds, Plus a Weekly Check (2026)
Crashlytics tells you why your Flutter app crashed. Android vitals in Play Console tells you how Google Play judges the result. The two overlap, but only one of them affects how visible your app is on the store. Google publishes overall bad-behavior thresholds of 1.09% for user-perceived crash rate and 0.47% for user-perceived ANR rate, plus an 8% per-phone-model threshold for both, assessed over the last 28 days. This guide explains what those numbers mean for an indie Flutter app and gives a 20-minute weekly check. It points to current public docs and is not a substitute for them.
What Android vitals measures
Android vitals is Play Console’s view of technical quality, built from data that opted-in Android devices report. Google’s Android vitals overview lists the core metrics: user-perceived crash rate, user-perceived ANR rate, excessive battery usage and excessive partial wake locks, alongside other signals such as startup time and slow rendering. The same page states that Play uses the last 28 days of data to assess quality and that staying under the bad-behavior thresholds helps maximize your title’s visibility on Google Play.
“User-perceived” is the important word. A crash or ANR that happens while the user is actively using the app counts; some background events do not. That is why your Crashlytics crash count and your vitals rate can tell different stories on the same week.
The thresholds that matter most
For phones, the published overall thresholds are 1.09% user-perceived crash rate and 0.47% user-perceived ANR rate, each averaged across devices. Separately, any single phone model above 8% on either metric counts as bad behavior for that model. Play Console Help’s Android vitals article explains that metrics above these thresholds appear as critical issues, alongside anomalies such as a sudden rise in ANR rate.
For a small app, the per-model threshold is the one that surprises people. If most of your users run two or three popular phones, one bad interaction with a specific device or Android version can push that model over 8% while your overall rate looks fine. Check the breakdown by device, not only the headline number.
Crash rate vs ANR rate in a Flutter app
A crash ends the process. In Flutter apps, many Dart exceptions are caught by the framework and never become native crashes, so the crashes vitals sees are often native: plugin code, platform channels, out-of-memory kills, or problems in the engine’s interaction with a specific device. Crashlytics with native symbol upload is the fastest way to read those stacks; our weekly Crashlytics triage post covers that routine.
An ANR (Application Not Responding) happens when the main thread is blocked. Android’s ANR documentation lists the triggers, including no response to an input event within 5 seconds. In Flutter apps, ANRs usually come from heavy synchronous work on the platform side — plugin initialisation at startup, large file or database work in a method channel handler, or a blocking call in a broadcast receiver — rather than from Dart code, which runs on its own thread.
The 20-minute weekly check
- Overview (3 minutes): open Android vitals and note crash rate and ANR rate against 1.09% and 0.47%. Write both numbers in a simple log.
- Critical issues (3 minutes): read any bad-behavior or anomaly entries and the date they started.
- Device breakdown (5 minutes): sort by phone model and check whether any model with meaningful traffic is near 8%.
- Release breakdown (4 minutes): compare the current version with the previous one; a jump after a release is your strongest lead.
- Cross-check (5 minutes): match the top cluster to a Crashlytics issue or an ANR stack, and create one ticket with the version, device and stack.
Twenty minutes is enough because the goal is detection, not diagnosis. Diagnosis happens in the ticket, on a day you can reproduce the problem.
When a metric crosses a threshold
If the rise lines up with a new release still in staged rollout, halting or pausing the rollout is usually the first move; our staged rollout rules explain how to set halt criteria before you need them. If the release is already at 100%, ship a targeted fix rather than a large refactor, and keep the change small enough to review in one sitting.
Because Play looks at 28 days, a fix does not clear the warning overnight. Expect the rate to fall gradually as fixed versions replace the old one on devices. Keep logging the weekly number so you can see the trend instead of refreshing the dashboard every hour.
Common Flutter causes worth checking first
- Plugins that do synchronous disk or network work during
Applicationor activity startup. - Large images decoded at full resolution, leading to memory pressure and kills on low-RAM devices.
- Platform channel handlers that block the main thread while waiting for a result.
- Outdated plugin versions with known native crashes after an Android or target SDK change.
- Startup that initialises every Firebase product before the first frame, instead of deferring what is not needed yet.
Startup work is also a performance issue, not only a stability one. Our post on Firebase Performance Monitoring triage shows how to watch startup traces alongside vitals, and Android’s app startup time guidance explains cold, warm and hot starts.
A simple vitals log for one-person teams
A spreadsheet with six columns is enough: week, app version at 100%, crash rate, ANR rate, highest phone model rate, and the one action you took. After a month you will know your normal range, which makes a real regression obvious and stops you reacting to noise. If you publish several apps, keep one row per app per week rather than one tab per app, so you can see at a glance which product needs attention.
Add a seventh column for release notes in plain words, such as “upgraded camera plugin” or “moved database init after first frame.” When a number moves, that column is usually where the explanation is hiding, and it costs seconds to fill in while the change is fresh.
What not to do
Do not suppress errors to make numbers look better: catching and ignoring a native exception can turn a crash into an ANR or silent data loss. Do not ship a forced update purely to reset metrics; vitals is assessed over a rolling window regardless. And do not compare your rate with another app’s screenshot — use the peer comparison inside Play Console, which is built for that purpose.
FAQ
Why does Crashlytics show more crashes than Android vitals?
They count differently. Crashlytics reports what your SDK captured, including non-fatal and Dart errors you choose to log; vitals reports user-perceived native crashes from opted-in devices.
Do the thresholds apply to every app?
The published thresholds are the same for phone apps; watch and wear apps have their own per-model values on the vitals page.
How long until a fix shows in vitals?
Gradually over the 28-day window, as users update to the fixed version.
Sources
- Android developers: Android vitals and bad-behavior thresholds (checked 2026-10-15)
- Play Console Help: monitor technical quality with Android vitals (checked 2026-10-15)
- Android developers: ANRs (checked 2026-10-15)
- Firebase Crashlytics docs (checked 2026-10-15)
More indie shipping notes on the gspteck blog.