Downloads Do Not Measure the App
My barcode app has been on the Google Play Store since May 2020. Six years later it has roughly a hundred installs, and the apps it sits next to in the search results have a hundred million. I spent most of those six years assuming that gap was a quality gap. It is not.
I want to be precise about this, because "why doesn't my good app get downloads" is three questions wearing one coat, and the three have three different answers. Conflating them is what keeps producing the wrong fix — which, in my case, was another feature.
The app is QR Code Manager. It is free, ad-free, fully offline, has twenty-five symbologies, a home-screen widget, a Quick Settings tile, URL-safety heuristics that catch decimal-encoded IP hosts and userinfo spoofing, twelve locales, and screenshot tests that fail the build if a layout breaks at 2× system font. I use it every single day. Play shows a handful of new installs a month, and by my own reading of the numbers, most of those people use it once and never return.
Here is what is actually happening.
The install count is a ranking number, not a quality number
The install decision happens in about three seconds, on a screen the size of a business card, containing an icon, a truncated title, a star rating, and one screenshot. Everything else — the full description, screenshots two through five, the changelog, the privacy section — is read by a rounding error of people who were already going to install.
So the honest accounting is that every feature past the first screenshot contributes nothing to the install rate. Not a little. Nothing. The URL-safety work is invisible at the point of purchase. The dedupe migration is invisible. The Kotlin-side Wi-Fi redaction, the text-scale screenshot tests, the twelve locales — invisible, all of it, to the only decision that produces an install.
That is not an argument for doing less of it. It is an argument for noticing that install count and app quality are measuring two different systems, and that improving one has almost no mechanical path to the other. I kept shipping into the wrong system and then reading the wrong number to see if it worked.
And the input to that three-second decision is rank. Nobody scrolls page three. Which brings us to the part I did not want to look at.
Ad-free is a product promise and a distribution handicap
I built an app with no ads, no subscription, no in-app purchases, and no analytics. I am not walking that back — it is most of the reason the app is pleasant to use, and the reason there is no HTTP client anywhere in its dependency list.
But it has a consequence I was slow to state plainly:
No ads → no revenue → no user-acquisition budget → no rank → no installs.
The hundred-million-install scanners are not out-executing me on features. They are running a loop I have deliberately disconnected. Ad revenue funds paid installs; paid installs buy rank; rank produces organic installs; organic installs produce more ad revenue. The thing I refuse to ship is the thing that pays for being found.
That loop is most of the answer to "why do they have 100M and I have 100." It is not a mystery and it is not a conspiracy. It is a funded growth engine versus no engine at all. I assumed for years that the rest of the answer was their head start — and when I finally checked, that turned out not to survive contact with the dates.
Independent developers usually discover this backwards. We treat "no ads" as purely an ethical choice with only upside, and then read the flat install graph as a verdict on the product. It is a verdict on the budget. The right response is not to bolt ads on; it is to accept that with no paid channel, the only remaining levers are the store listing itself, retention, and word of mouth — and to actually work those instead of shipping feature twelve.
The app that beat me started after mine did
I had been carrying a comfortable picture of the incumbents: ancient apps with a decade of head start I was never going to close. Then I actually read the two listings sitting next to mine in the results.
| QR & Barcode Scanner | QR Code Scanner & Scanner App | QR Code Manager | |
|---|---|---|---|
| Developer | Gamma Play | "QR Code Scanner." | me |
| On the store since | Mar 2015 | Apr 2021 | May 2020 |
| Installs | 500M+ | 100M+ | ~100 |
| Rating | 4.8 (4.61M reviews) | 4.7 (530K reviews) | — |
| Monetisation | Ads | Ads + in-app purchases | None |
| Last updated | Aug 2026 | Aug 2026 | Aug 2026 |
Read the second column twice. That app went on the store in April 2021 — eleven months after mine — and it has at least a hundred million installs. Whatever separates us, it is not a head start.
It is not the platform either. That app did its growing straight through the window in which Android 13 shipped the system scanner tile, in the category I have just finished describing as structurally doomed. The category being absorbed by the OS is true, and it is still not what happened to me.
Then look at the package names, which are chosen once and never seen by a user. Mine is app.ideatools.qrscan — an organisation and a product. Theirs is:
qrcodescanner.barcodescanner.qrscanner.qrcodereader
Four search terms concatenated into an identifier, and the developer's name on the listing is "QR Code Scanner." — the keyword, with a full stop, registered as a company. None of that is an accident, and none of it is about scanning quality. It tells you what the app was built around before a line of it was written.
The last thing worth saying plainly is the row I least wanted to write. Both of them carry ads, one carries ads and purchases, and both hold ratings above 4.7 across half a million to four and a half million reviews. The story where the big apps are ad-riddled garbage that users merely tolerate is not supported by those apps' own review pages. They are ad-riddled, and people rate them 4.8.
So the honest ordering of what separates a hundred installs from a hundred million goes: a funded acquisition loop, then a listing built around the query, then review count acting as both ranking input and social proof — and then, somewhere far down the list, whether the app is any good.
I am selling a wallet in the scanner aisle
Here is the specific mistake, and it is mine, not the market's.
Somebody searching "qr scanner" wants a verb. They want to point a phone at a code. A store title promising a "personal barcode and micro-info wallet" does not match that query, does not rank for it, and does not convert the person who does see it — because they did not come shopping for a wallet.
Meanwhile the marketing plan I wrote for this app opens with the wallet framing and also promises the fastest ad-free scanner, and my store title tries to carry both. Splitting the difference on positioning does not get you half of each audience. It gets you neither, because a listing that is about two things reads as being about nothing.
There is a harder fact underneath it. The operating system ate the verb. Android 13 shipped a QR scanner Quick Settings tile as a system feature — the tile is in the shade, and it hands off to Google Lens. iOS put it in the camera app years earlier. Scanning a QR code is now a built-in OS capability on every phone shipped in the last several years.
So the category I am competing in is one where the core job has been absorbed by the platform. Those hundred-million numbers are cumulative counters accumulated largely before that happened — they are a record of past demand, not a measure of current demand. Ranking first in a shrinking category would still not be a good business. I have been treating the incumbents' download counts as a target when they are closer to a fossil.
I should not be allowed to hide behind that, though, and the dates do not let me. My app went on the store in May 2020, more than two years before Android 13 shipped that tile. There was a window in which the category was still real and I was already standing in it, and nothing happened during that window either. The platform absorbing the job explains why competing for "qr scanner" is a bad bet today. It explains nothing about 2020 to 2022. The only thing that explains those two years is that I uploaded an app and called it a launch.
The wallet idea, on the other hand, is not a job the OS does. Nobody's phone has a good home for "the forty short strings my life runs on." That is the actual opportunity, and it is the one thing my store listing is too hedged to claim clearly.
"Downloads then stops" is a different bug
This is the part that took me longest, because I kept filing it under the same heading as the install problem. It is not the same problem. It is the reverse one.
Time-to-value for a scanner is about three seconds and requires zero user input. Point at code, get result. The app is useful before you have done anything.
Time-to-value for a wallet is about three weeks and requires the user to type in their own data first. And look at what my best features actually depend on:
| Feature | What it needs before it does anything |
|---|---|
| Home-screen widget | A saved code, pinned |
| Quick Settings tile | A saved code, pinned |
| Tag filter chips | Several codes, tagged |
| Pin vs. bookmark | Enough codes that ordering matters |
| Search | Enough codes that browsing fails |
| Default ordering | A usage history |
Every one of them is invisible on day one. A new user opens the app to an empty list, scans one thing, and has now seen the entire product as far as they can tell — a scanner, slightly nicer than the one built into their phone, which they will not open again because their phone has one built in.
They came for the verb. They got the verb. The noun — the thing that would actually make them keep it — is behind a wall of data entry they have no reason to do yet, because I never told them the wall was there or what was on the other side.
It is worth being concrete about what is on the other side of that wall, because the two things I now reach for most were things I could not have demonstrated to anybody on day one.
I live between countries and carry a local phone number in each. When somebody asks for my number I have stopped trying to say it — I cannot reliably recall a number I have had for four months, and reading a string of digits aloud in a language I am still learning is its own small ordeal. I open the app and show them the screen, where phone numbers are enlarged automatically. Separately, six months of working in Taiwan means a restaurant bill is only reimbursable if the invoice carries my employer's eight-digit 統一編號 — a number I need about twice a month, which is precisely the frequency at which a number refuses to stick. At the till I hold up the screen and the cashier types it in.
Both of those are, I think, genuinely good reasons to keep an app installed. Neither is reachable in week one. The first requires living in more than one country. The second requires taking a job in Taiwan. The payoff is gated on your circumstances, not on your effort — and that is a harder problem than a data-entry wall, because no amount of onboarding manufactures the day somebody asks for your phone number in a language you cannot pronounce it in.
So this is not a marketing failure, and it is mostly an onboarding failure — but onboarding can only do the smaller half of the job. It can make the wall legible and one step tall. It cannot make the situation arrive any sooner. What it has to buy me is that the app is still installed on the day it does.
What I would actually change
Four things, in descending order of how much I think they matter and ascending order of how much I want to do them.
Solve the empty state. Right now an empty library says "no saved codes." It should demonstrate the product: a few example rows a new user can see the shape of — a Wi-Fi code, an address, a phone number, a company tax ID — with one obvious action to replace them with their own. The wall has to be visible and one step tall. And the examples should be chosen for the situations they imply rather than for coverage of payload types, because the thing I actually need a day-one user to leave with is not a filled-in library. It is the sentence "I will want this the next time somebody asks me for a number I can't say out loud."
Pick one job for the listing and commit. Either win the scanner query with a scanner listing and reveal the wallet through onboarding, or stop competing for the scanner query at all and go after the searches that have no incumbent — the address, the carrier code, the guest Wi-Fi. Both are defensible. Hedging is not.
Make screenshot one carry the whole promise. It is functionally the entire listing. Mine currently shows a screen, not a claim.
Change which number I look at. Cumulative installs is the one metric I cannot act on — it aggregates a decade of decisions into a number that only goes up. Store-listing conversion rate and day-1/day-7 retention are both in Play Console, both actionable, and both were sitting there in 2020 waiting to tell me I had a positioning problem and an empty-state problem rather than a feature problem.
Notice that exactly none of these is "write more app."
The part that generalises
The thing I got wrong is not specific to app stores. It is that distribution is a separate product from the thing being distributed, with its own design work, its own failure modes, and its own feedback loop — and building the first one well produces no progress at all on the second.
"Build something good and they will come" is not wrong because good things don't spread. It is wrong because spreading is a mechanism, and mechanisms need an energy source. Ad-funded apps have one. Venture-funded apps have one. Products with a viral loop or a network effect have one. A free, ad-free, offline utility with no account and no sharing surface has, by construction, none — and I made every one of those choices on purpose without ever noticing that together they added up to a distribution strategy of hoping.
That is still a defensible position. There is real value in a tool that exists because someone needed it, funded by nothing, accountable to nobody, that will never be sold or enshittified. But it should be chosen as a stance, with its consequences stated up front, rather than discovered six years later while staring at a flat graph and concluding the problem must be that the settings screen isn't good enough.
The May 2020 release date, my own install figures and the shape of my retention are my records and my reading of Play Console on 23 August 2026, not audited numbers — and the current codebase is a 2026 Flutter rewrite, so the six years refer to the listing rather than to one continuous body of code. Competitor figures were read from the listings linked above the same day; Play reports installs as rounded tiers, so "100M+" and "500M+" are floors, not measurements.