Android App Startup Time: What 12 Testers Can Measure
How to measure Android app startup time with 12 testers: cold starts on a release build, five runs per device, median not average, and why vitals stays empty.
On this page11 sections
- 01The three start states are three different numbers
- 02Why Android vitals will not show your startup time at 12 testers
- 03A five-run cold-start protocol any tester can run
- 04What to ask the tester to send back
- 05Reading twelve devices instead of one average
- 06What testers usually mean by slow
- 07Where the delay normally is in a small app
- 08Turning startup numbers into production-access evidence
- 09When to stop doing this by hand
- 10Frequently asked questions
- 11Sources
The startup number worth acting on has a precise definition: cold start, release build, after a force-stop, five runs, reported as a median for each device. Not one launch. Not a debug build. Not an average across twelve different phones.
There is a second problem that most startup guides skip. During closed testing, the Start-up time page in Android vitals will usually be empty. Play Console only reports metrics collected from users who opted in to share usage and diagnostics on a subset of devices, and it only displays a metric once it has enough data to publish an anonymised report. Twelve testers rarely clear that bar, so waiting for the dashboard is a waste of the 14 days you have.
This is the tester-facing half of Android app performance testing: how to get a trustworthy cold-start figure out of a group of people who do not have Android Studio, and how to read what comes back without fooling yourself.
The three start states are three different numbers
Google's App startup time documentation defines launch in three states, and the same app can show wildly different figures in each. A cold start creates the process from scratch. A warm start reuses the process but recreates the activity. A hot start brings an existing activity back to the foreground with the UI still resident in memory.
That is why a tester who "closed and reopened" the app is not measuring what you think they measured. Cold starts are the expensive case, and Google's guidance is explicit about which one to optimise: "We recommend that you always optimize based on an assumption of a cold start."
| State | What the system recreates | Android vitals flags it as slow at | Google's performance goal |
|---|---|---|---|
| Cold | Process, Application object, main thread, activity, first draw | 5 seconds or more | 500ms or less |
| Warm | Activity, using the saved instance state; process may survive | 2 seconds or more | 200ms or less |
| Hot | Nothing if the UI is intact; the activity is just brought forward | 1 second (Play Console help) or 1.5 seconds (Android Developers) | 150ms or less |
The hot-start row is not a typo. As of November 2026 the Play Console help page states that a slow hot start is "1 second or more", while the App startup time page in the Android vitals section of developer.android.com states 1.5 seconds or more. Both are Google pages, both are live, and they disagree. If a hot start is your problem, treat one second as the threshold, because that is the stricter of the two readings.
Two metrics sit underneath all three states. Time to initial display (TTID) is when the first frame appears, and the framework reports it for every app automatically. Time to full display (TTFD) is when the app is genuinely usable, including content loaded after that first frame, and the system cannot infer it: your app has to call reportFullyDrawn() or no TTFD is reported at all.
Why Android vitals will not show your startup time at 12 testers
Play Console collects Android vitals data from "users who have opted in to automatically share usage and diagnostics data from a subset of Android devices and OS versions", and Google's own documentation adds that metrics are only shown once there is enough data to generate anonymised reports. Startup is also recorded only when a user actually triggers an activity, and if an app starts several times in a day from the same state, only the day's maximum is kept.
Put those three conditions together and a closed test with twelve people produces, at best, a handful of sessions spread over a few devices, for one app version, inside a dashboard that keeps 90 days of history. Expecting a startup line to appear is optimistic. When it does appear, the sample is so small that the 90th percentile is meaningless.
There is one more trap in the collection rules that matters more than it looks: start-up time is tracked when the first frame completely loads, "even if it isn't a screen that users interact with", and Google's example says that if an app starts with a splash screen, the startup time equals the time required to display the splash screen. A splash screen can therefore improve the number Google records while leaving the actual wait unchanged. If your testers describe a long wait but the metric looks fine, this is usually why.
A five-run cold-start protocol any tester can run
You do not need Android Studio on a tester's machine. You need USB debugging enabled, one command, and five numbers from each device. The workflow below is the whole loop, and it is short enough to paste into a tester brief.
Step one: install the release build from the closed-testing track, not a debug APK from a laptop. Debug builds are not representative, and R8 minification changes startup behaviour enough that a debug number cannot be compared with anything you ship.
Step two: force-stop the app so the process is gone. Step three: launch it with the activity manager and let it wait for the launch, using the command Google documents for measuring TTID:
adb shell am start -S -W com.example.app/.MainActivity \
-c android.intent.category.LAUNCHER \
-a android.intent.action.MAIN
The -S flag force-stops the package before starting it, which is what makes the run cold. The -W flag waits for the launch to finish so the terminal prints the timing block instead of returning immediately.
Step four: read the output. You get three values, and they answer three different questions. TotalTime is the launch cost from process creation to the last activity in the chain being displayed, which is the figure to record. ThisTime covers only the final activity, so it hides any work done in an earlier one. WaitTime also includes the transition away from whatever screen was in front, so it is a system figure rather than an app figure. On a simple single-activity launch the three are usually within a few milliseconds of each other, and that agreement is a good sanity check that the run was clean.
Step five: repeat five times and keep the median. The first launch after install does extra work, and one run on a phone that was background-syncing photos is not a measurement. If the five numbers scatter widely, that scatter is itself the finding: a startup time that varies by two seconds usually means disk I/O or a network call is on the critical path.
What to ask the tester to send back
The most common failure in tester-collected performance data is not a wrong number, it is a missing one. A tester who sends "it opened in about two seconds" has given you nothing you can compare. Ask for a fixed set of fields so twelve reports can be read side by side.
| Field | What the tester sends | Why it matters |
|---|---|---|
| Device and OS | Exact model name and Android version | A 2019 budget phone and a current flagship are not the same test |
| Build | Version name and version code from the Play listing | Numbers are only comparable within one release, and vitals segments by app version |
| Five readings | The TotalTime value from each of five cold launches | One number cannot show variance; five can |
| Cold or warm | Confirmation the force-stop was run before each launch | A relaunch from the recents screen is a hot start and will look deceptively fast |
| Screen recording | Thirty seconds, starting on the home screen, tapping the icon once | Shows the wait the number does not capture, including content that arrives after the first frame |
| Network state | Wi-Fi, mobile data, or airplane mode | Separates a startup problem from a first-screen network problem |
For testers who genuinely cannot install platform tools, the fallback is weaker but not worthless: a screen recording of ten launches with the screen recorder's own timestamp, described as such. Say plainly in your notes that these are impressions with a video attached, not TTID readings, so nobody later compares them with the numbers from a phone that ran the command.
Reading twelve devices instead of one average
Do not average the twelve results. A mean that mixes a 700ms flagship with a 4.2-second budget phone describes no real user, and it will hide the exact device class your first paying customers are holding. Report per device, then look at the spread.
Our own work on closed-testing campaigns shapes how we read those reports. Across the campaigns we have run, the widest startup gaps are almost never between two recent flagship phones; they appear between a current device and an older or lower-memory device in the same test group, which is the same reason a mixed device pool is worth keeping rather than replacing with twelve identical phones.
Two honest limits apply. First, twelve devices do not produce a percentile: Google's dashboard works in 90th and 99th percentiles of daily sessions, and sixty launches cannot support that. Report minimum, median and maximum per device, and say the sample is small. Second, a single device showing 6 seconds while the other eleven sit near 1.2 seconds is not automatically a bug in your app. It can be that device's storage, a thermal state, or a background sync. Ask for a recording before you open a fix.
What testers usually mean by slow
The phrase "the app is slow to open" maps onto four different failures, and only one of them is a startup problem in the technical sense. Sorting the report before you profile saves a day.
| What the tester reports | Most likely cause | What to ask for |
|---|---|---|
| A blank or white screen for several seconds | Heavy Application or activity initialisation before the first frame | Five TotalTime readings plus a Perfetto trace from your own device |
| The screen appears, then spins | TTFD problem: first frame is fine, content arrives late | Whether reportFullyDrawn is called, and the recording's timeline |
| Only the first launch after install is slow | Install and first-run work, not steady-state startup | Readings from launches two to six, not launch one |
| Slow only on mobile data | Network call on the critical path, not startup code | Two sets of readings, one on Wi-Fi and one with airplane mode |
| Slow on an emulator but fine on a phone | Not a measurement; emulator timing is not device timing | Physical device readings, and drop the emulator result from the report |
Emulator results are worth calling out because they recur in closed tests where a tester cannot install on a real phone. An emulator shares CPU with the host and has no real storage latency, so its startup figure is neither a floor nor a ceiling. It cannot be used as evidence of anything except that the app launches.
Where the delay normally is in a small app
Google's documentation names two clusters, and they match what we see in single-developer apps built quickly with a framework or an AI builder: heavy app initialisation and heavy activity initialisation.
On the app side, the usual culprits are work in Application.onCreate for screens the launch intent may never show, SDKs that initialise themselves through a merged-manifest content provider, and disk reads or deserialisation on the main thread. Each content provider is expensive to instantiate, and Android initialises them in an order you do not control, which is why removing one unused analytics SDK sometimes buys back several hundred milliseconds.
On the activity side, it is a deep view hierarchy, composables doing real work during the first composition, synchronous database or network calls before the first draw, and bitmap or vector decoding at first use. If your app shows a splash screen while that work happens, the number improves and the experience does not.
A quick ordering heuristic that holds up in practice: if TotalTime is large but the screen appears fully populated, the cost is before the first frame and lives in initialisation. If TotalTime is small and testers still complain, the cost is after the first frame and lives in data loading.
Turning startup numbers into production-access evidence
A cold-start median before and after a fix is one of the few concrete, checkable statements you can put in front of a reviewer. "Cold start on a Redmi Note 10 went from 3.9 seconds to 1.6 seconds across five runs after we moved SDK initialisation off the main thread" describes work that happened during the test, on a real device, with a measurement attached.
That belongs in the answer about what changed because of testing, not in the answer about who your testers were. The production access form asks three broad things, and a performance number only supports one of them; padding the other two with it reads as filler. If you are still drafting those answers, our walkthrough of the production access questions and what to write maps each question to the evidence that satisfies it.
The startup readings also belong in the bug report that goes with the fix, alongside the device and build, so a later regression can be compared against a recorded baseline rather than a memory. Our bug report template for closed testing has a slot for measured values for exactly this reason.
Two related checks are worth doing in the same pass. If testers cannot install the build at all, that is not a performance problem, and whether emulators count as testers explains why a device pool made of emulators will fail the 14-day requirement regardless of how fast the app starts. And if your app ships native libraries, the 16 KB memory page size requirement can affect load time on newer devices, so rule it out before you chase a startup regression.
When to stop doing this by hand
The five-run protocol is for the closed-testing phase, where the goal is a defensible number from real devices rather than a benchmark suite. Once you are iterating on startup weekly, move to Macrobenchmark's StartupTimingMetric, which reports timeToInitialDisplayMs and timeToFullDisplayMs over controlled iterations and outputs minimum, median and maximum. Google's guidance for that metric is to focus on the median when judging an improvement, because it estimates typical user experience rather than a lucky run.
Baseline Profiles are the other lever worth knowing about at this stage. Google states that they improve code execution speed by about 30% from the first launch by avoiding interpretation and JIT compilation for the included code paths. That is Google's published figure, not a result you should assume for your app; measure before and after on the same device.
Frequently asked questions
Does Android vitals measure startup time during closed testing?
It can, but it usually will not show you anything useful. Android vitals collects from users who opted in to share usage and diagnostics on a subset of devices, and Play Console only displays a metric once it has enough data for an anonymised report. With twelve testers and a few launches each, you are unlikely to clear that bar inside the two weeks of a closed test.
Should I report cold start or warm start to my testers?
Cold start. It is the state with the most work to do, it is what Google recommends optimising for, and it is reproducible: force-stop the app, then launch. A warm or hot start number will look better and tells you little, because the process and sometimes the UI are already in memory.
Why does adb show 3.5 seconds when Play Console shows 1.9 seconds?
The two are not measuring the same window. Play Console reports TTID as observed on opted-in devices, while the command line reports its own launch timing that includes the force-stop and start sequence. Device class also differs: your test phone and the median vitals device may not be comparable. Use one method consistently and state which one produced the number.
Do I need to call reportFullyDrawn to measure startup?
Not for TTID, which the framework reports automatically. You do need it for TTFD, because the system cannot know when your asynchronously loaded content is on screen. If you call it before the first frame, Google warns that both values are reported as the same number, so the figure flatters you and measures nothing.
Will a splash screen fix a slow startup?
No, it changes what gets measured. Google's collection notes say that if an app starts with a splash screen, the recorded startup time equals the time needed to display the splash. The user still waits the same total time, and anything loading behind the splash is invisible to a TTID-based metric.
Can testers measure startup without Android Studio or a rooted phone?
Yes. They need USB debugging enabled, a USB cable and the platform tools installed, then one am start -S -W command per launch. No root, no developer build, no profiler. If they cannot install platform tools, a screen recording of ten launches is weaker but still usable evidence.
How many runs are enough?
Five per device is a reasonable floor for a closed test: enough to see whether the number is stable, short enough that a tester will actually do it. If the five readings vary by more than about a second, collect more rather than averaging the five you have, because the variance is the finding.
Do app updates invalidate the measurement?
They reset the comparison, because a startup figure is only meaningful for one build. Android vitals also segments data by app version, which is why an update can make the dashboard appear to change overnight. Record the version code with every set of readings.
Sources
- Android Developers: App startup time (cold, warm and hot states, TTID and TTFD, the Logcat Displayed line, the
am start -S -Wcommand, reportFullyDrawn behaviour) - Android Developers: App startup time in Android vitals (excessive thresholds: cold 5 seconds, warm 2 seconds, hot 1.5 seconds; TTID is the metric used)
- Play Console Help: Monitor your app's technical quality with Android vitals (opted-in data collection, 90 days of history, slow-start thresholds including hot start at 1 second, splash screen and daily-maximum collection rules)
- Android Developers: Overview of measuring app performance (cold start under 500ms, warm under 200ms, hot under 150ms, percentiles close to the median)
- Android Developers: Macrobenchmark metrics (StartupTimingMetric values and the advice to judge improvements on the median)
- Android Developers: Baseline Profiles overview (roughly 30% faster code execution from first launch)
Need testers who stay opted in for the full 14 days?
OnTesters provides 12 real testers on physical Android devices, with replacements for dropouts and free retesting if Google asks for more testing. From $14.99.
We do not sell or guarantee production access
Afrin Asha
Founder, OnTesters
Android developer and QA specialist. Built OnTesters after working through Google Play’s 12-tester closed testing requirement on real devices. Read the full story