Broken Functionality policy: why Google rejected an app that works fine on your phone

Google sent you one line: your app isn't compliant with the Broken Functionality policy. No stack trace, no screenshot, no steps to reproduce. You install the same release build on your own phone and it works. So what do you change before you resubmit? Usually nothing in your code — the reviewer never got that far.

Last updated: July 2026

What the Broken Functionality policy actually says

Broken Functionality is a section of Google Play's “Functionality, Content, and User Experience” policy. The rule is one sentence: “We don't allow apps that crash, force close, freeze, or otherwise function abnormally.” Google gives exactly three examples — apps that don't install, apps that install but don't load, and apps that load but are not responsive.

Read that again and notice what isn't in it. Nothing about your architecture, your test coverage, your framework, or your code quality. It's a behaviour policy. It describes what happened on one device, in one session, on one network, during a review that lasts minutes. That distinction is the whole game: you can't fix it by writing better code, only by making the app survive a stranger's first five minutes.

Google Play policy: Functionality, Content, and User Experience

Find your exact rejection line

The email body is boilerplate sent to thousands of developers. The issue line under it is not — it's the closest thing to a bug report you're going to get. Find yours in the first column.

The line Google gave youWhat the reviewer sawThe cause that's actually most likelyDo this before you resubmit
App doesn't installThe artifact never became a working install on the review device.An install-time failure, not a runtime bug: minSdkVersion above the test device, a missing ABI or density split, or a signing mismatch.Install the artifact Google actually has — download it from your internal testing track, not from Android Studio — on a device that matches your declared minSdk.
App installs, but doesn't loadIt launched, then sat on a screen that never became usable.The splash is waiting on something the reviewer's session doesn't have: an auth token, a first API call, a remote config fetch, an FCM token.Cold-start the app in airplane mode, with no cached session. If it hangs instead of showing an error, you just reproduced your rejection.
App loads, but crashesA crash in the first minutes of the session.A first-run path you never hit locally. Your device has data; the reviewer's has none, so an empty list or a null profile takes down the screen.Pre-launch report → Stability tab. The stack trace is already sitting there, from a real device, on Google's side.
App loads, but is not responsiveTaps did nothing, or the UI froze.Main-thread work on startup: a synchronous network call, a large JSON parse, a database migration.Move it off the main thread. Android fires an ANR at 5 seconds of an unhandled input event — a reviewer gives up well before the system does.
App contains icon(s) or button(s) that are not responsiveSpecific controls did nothing when tapped.Dead controls: a “Coming soon” tile, a CTA behind a feature flag that's off, a menu row wired to nothing, a link that 404s.On a clean install with no account, tap every control in the app. Anything that doesn't respond gets wired up or removed — there's no third option.
Issue lines as they appear under the Broken Functionality verdict in the Play Console. The first, third and fourth are Google's own published examples; the others are recurring strings reported on the Play developer community.

Broken Functionality is not Limited Functionality

These are two different sections of the same policy page, and they have opposite fixes. Broken Functionality means your app fails. Limited Functionality and Content means your app works perfectly and still isn't worth installing — a webview wrapper of your website, a single static screen, a viewer for one PDF. Getting the two confused sends you off building features when you should be fixing a hang.

Broken FunctionalityLimited Functionality and Content
The rule“We don't allow apps that crash, force close, freeze, or otherwise function abnormally.”“We do not allow apps that only have limited functionality and content.”
What went wrongYour app didn't do what it says it does.Your app did exactly what it says. That's the problem.
Typical triggerHung splash, crash on first launch, dead button, unreachable backend.Website in a WebView, one text screen, a wrapper with no native value.
The fixMake the existing flow work on a clean device.Build something a browser tab can't do — or don't ship it.
The wrong moveAdding features.Bug-fixing.

Our own Google Play rejections guide used to fold both of these into a single bullet. That was wrong, and it's a large part of why this page exists. Why Google Play rejects apps

Your app works. The reviewer still couldn't get in.

This is where most of these rejections actually live, and almost nobody writes about it. Your build is fine. Your machine is not the reviewer's machine. Go through this list before you touch a line of code.

  • A login screen with no working test credentials. The reviewer opens your app, sees a sign-in form, has nothing to type, and closes it. From the outside that is indistinguishable from an app that “installs, but doesn't load”.
  • SMS or email OTP. You supplied a demo account, but the code goes to a phone on your desk. Google is explicit: if your app normally needs 2-step verification or a one-time password, you must supply reusable credentials that bypass it.
  • A geo-gated or IP-allowlisted backend. Review isn't run from your office. If your API allowlists your office CIDR, or the app blocks countries you don't sell in, the reviewer lands on your error screen. Google's own wording is that sign-in details must be valid “regardless of user location”, and that a geo-gate needs master credentials.
  • A staging or localhost base URL in the release build. It sounds too dumb to happen and it happens constantly — a build variant misconfigured, a .env not swapped, a debug URL surviving a merge. Your laptop resolves that host through the office VPN or an /etc/hosts line. The review device doesn't.
  • A backend that sleeps. Scale-to-zero and free-tier hosting cold-start in 5 to 30 seconds. Your first request of the morning is slow and you've stopped noticing. Every request the reviewer makes is a first request of the morning.
  • A feature flag left off. You shipped with the remote flag disabled, planning to flip it after approval. The reviewer tests what's in front of them, finds an empty screen, and rejects.
  • An expired API key, or a Maps/Firebase key restricted to your debug signing certificate. Play App Signing re-signs your release with a different SHA-1 than your debug key. Every tile and every call then fails — in production only, never on your machine.

Every one of these produces an app that is flawless on your desk and broken in review. And none of them will ever show up in your crash reports, because nothing crashed.

How do I give Google Play reviewers a test account?

In the Play Console, go to Policy and programs → App content → Sign-in details → Start (or Manage), then click “+ Add new instructions” and fill in the access details. You can add up to five sets. Then open the Publishing overview page and click “Send for review”. If credentials are the only thing you changed, you don't need to upload a new .aab.

Google's requirements for those details, in their words:

  • Accessible at all times, reusable, and valid regardless of user location.
  • Maintained at all times without any error.
  • Provided in English.
  • If sign-in isn't numeric or alphanumeric — a QR code or barcode — generate a static URL and upload it to the Play Console.
  • If the user sets their own PIN or password to reach in-app content, give clear instructions.
  • If you rely on Sign in with Google, Facebook or similar, provide all the account information plus detailed instructions.

The failure mode nobody warns you about: your demo account works, and then it doesn't. A 30-day trial lapses. A rate limiter blocks it on the third review. Someone on the team resets the test database on a Friday. “Accessible at all times” is doing a lot of work in that sentence — treat the review account as production data.

One account isn't enough either. The reviewer has to reach every feature your store listing advertises. If the premium tab needs a paid plan, the demo account needs that entitlement already granted.

Google Play: requirements for providing sign-in details for review

The pre-launch report lies to you if you have a login screen

Robo test can only type your test credentials into standard Android widgets and Compose. It cannot sign in through a WebView-based auth flow, and it can't drive controls your app renders in OpenGL. So a React Native or Flutter app with a WebView login gets a clean, crash-free pre-launch report covering exactly one screen: the login screen. Green report, rejected app.

Add a throwaway test account under Test and release → Testing → Pre-launch report → Settings. Never put a real account there. Then read the Screenshots tab before the Stability tab — if all 20 screenshots are your login screen, you've found your rejection and it was never a crash.

Google Play: use a pre-launch report to identify issues

How slow counts as frozen?

Android raises an ANR when your app doesn't respond to an input event within 5 seconds. The same 5-second limit applies to a foreground broadcast receiver, and to calling startForeground() after startForegroundService(). Those are the system's limits. A reviewer's patience is far shorter, and there is no appeal against boredom.

For context on the numbers Google itself considers unacceptable: the Android vitals bad-behaviour thresholds are a 1.09% user-perceived crash rate and a 0.47% user-perceived ANR rate across devices, or 8% on any single phone model. Cross those and your store listing gets a warning — but you can sit well under them and still be rejected, because review is one session, not a distribution.

Here's what that looks like in practice. A developer posted the exact string “App installs, but doesn't load” to the Android Builder forum, insisting nothing was wrong; pressed for detail, he mentioned that “sometimes the screen 1 usually pause for few seconds”. No crash. No ANR. Under the 5-second system limit. Rejected anyway.

Which brings us to the single most efficient way to earn this rejection: the splash screen that hides a dead backend. It looks identical whether your API answered in 200 ms or never answered at all. Give it a timeout — 3 seconds, then a real error screen with a Retry button. An app that says “Couldn't reach the server” is a working app having a bad day. An app that spins forever is “installs, but doesn't load”.

Android developers: ANRs · Android vitals thresholds

Reproduce it in 30 minutes

  1. Get into the reviewer's state. A wiped emulator or a spare device: no account signed in, no cached session, no VPN, no /etc/hosts entry, mobile data instead of office wifi. Install the artifact Google has — download the .aab from your internal testing track rather than building locally. This step alone finds most of them.
  2. Open the pre-launch report (Test and release → Pre-launch report). Screenshots tab first: did the crawler get past your login? Then Stability for the stack trace, and Performance for the startup time.
  3. Run adb logcat while cold-starting, filtered to your process: adb logcat --pid=$(adb shell pidof -s com.your.package). Watch for the request that never returns. That's your splash hang.
  4. Check Crashlytics, and Play Console → Quality → Android vitals → Crashes and ANRs, filtered to the version code you submitted. If both are empty, your problem was never a crash — go back to the reviewer-environment list above.
  5. Walk your own store listing. Open every screenshot, read every feature sentence, and do exactly that in the app on the clean device, in order.

Your store listing is the test script

Reviewers don't guess what your app is supposed to do. They read your listing and your screenshots, and then they check. That makes your own marketing copy the spec you're graded against. A screenshot of a feature that ships next month is a broken feature today. So is a “Coming soon” tile, a Settings row that opens nothing, and a support link pointing at a 404. Cut the screenshot or ship the feature.

Resubmit, or appeal?

Resubmit if you found a concrete cause and fixed it: new version code, App content updated, Send for review. Appeal only when you're confident nothing is broken and you can show it — you get one appeal per enforcement action, and the reply typically lands in about 2 business days.

Blunt advice: most of the “nothing is broken in my app!!!” threads on the Play community end with the developer finding a login wall or a sleeping backend. Do the 30-minute pass first. If you appeal and you're wrong, you've spent your one appeal and a week of revenue.

Either way, say what changed. Google's reviewers are working from the same one line you are. Paste this into the appeal form, or into the Sign-in details instructions field when you resubmit:

brokenFunctionality.template

Apple's version of the same rejection

Apple calls this Guideline 2.1 — Performance — App Completeness, and it's their most-cited rejection reason. Same root causes, different console: the demo account goes in App Store Connect → your app → App Review Information, with the “Sign-in required” toggle on, plus the Notes field for anything a stranger couldn't guess. One difference matters a lot in practice — Apple usually tells you which screen failed and attaches a screenshot. Google gives you one line. That asymmetry is why the decoder table above had to exist.

The most common App Store rejection reasons

What we can check for you — and what we can't

Upload the .aab or .apk you're about to submit and we read its manifest. Of the 24 Android checks in the tool, 10 run automatically, and four of them map straight onto Broken Functionality causes:

  • usesCleartextTraffic — an http:// base URL that works on your machine and is silently blocked in a release build on Android 9+.
  • android:debuggable — a debug build shipped by accident, which is an instant rejection on its own anyway.
  • MAIN/LAUNCHER activity — no launchable entry point is, quite literally, “app doesn't load”.
  • targetSdkVersion and minSdkVersion — the mismatch behind “app doesn't install” on a review device.

The other 14 are the questions no parser can answer for you, and three of them are this exact policy: is every feature functional with no placeholder or broken links, have you tested on real devices and checked Android vitals, and does the app do something real beyond a website wrapper.

What we can't do, plainly: we don't run your app. We can't tell you your backend is asleep, your demo account expired last Tuesday, or your Maps key is bound to the wrong SHA-1. No tool that parses a binary can. That's what the 30-minute pass is for.

FAQ

What does “Your app contains content that isn't compliant with the Broken Functionality policy” mean?

It means Google's reviewer opened your app and it crashed, froze, or never became usable. It's a behaviour verdict, not a code review. The short line after it — for example “App installs, but doesn't load” — is the only diagnostic you get, so start there.

My app works perfectly. Why does Google say it's broken?

Because the reviewer isn't on your device or your network. A login screen with no test credentials, an API allowlisted to your office IP, a staging URL in the release build, or a sleeping backend all produce an app that fails for them and works for you. None of it shows up in crash reports.

Do I need to upload a new .aab to fix a Broken Functionality rejection?

Not always. If the cause was missing or expired sign-in details, you update them under Policy and programs → App content → Sign-in details and click Send for review on the Publishing overview page — the existing build is resubmitted. If the cause is in the app, you need a new version code.

Does the pre-launch report catch Broken Functionality issues?

Partly. Robo test finds crashes and ANRs on real devices, but it can't sign in through a WebView-based login and can't drive OpenGL-rendered controls. If your app has a WebView login, the report will look clean while covering only the login screen. Check the Screenshots tab to see how far the crawler actually got.

Can I appeal a Broken Functionality rejection?

Yes — one appeal per enforcement action, with a reply usually within about 2 business days. Only appeal if you've reproduced the reviewer's conditions on a clean device and genuinely found nothing. Otherwise fix the cause, bump the version code, and resubmit; that's faster than losing the appeal.

How long does approval take after I resubmit?

Google gives no guaranteed turnaround, and it varies from a day to a couple of weeks depending on the account and the violation history. Plan for the resubmission to be your last one: a second Broken Functionality rejection on the same app costs far more time than the 30-minute diagnosis pass would have.

Sources

Check your build before you submit

Run your .ipa or .apk through App Review Checker and catch these issues in seconds.

Check an app