mcpField
P
playstore-review

playstore-review

github.com/devsemihTesting & quality10238 installsUpdated 15w ago
Repository

About playstore-review

playstore-review audits Android projects for potential Google Play policy violations before submission. It is aimed at developers and release teams, supports checks across multiple Android frameworks, and prioritizes findings by rejection risk.

Key features

  1. 01Detect Android project frameworks
  2. 02Inspect manifests and build configuration
  3. 03Review privacy and data safety
  4. 04Check sensitive permissions and APIs
  5. 05Assess billing, ads, and policy risks

Use cases

  1. 01Audit an app before Google Play submission
  2. 02Check whether permissions match core functionality
  3. 03Compare data safety disclosures with SDK collection
  4. 04Find billing or account-deletion compliance issues

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/devsemih/appstore-review-skill --skill playstore-review

After installing, type/playstore-reviewin Claude Code to confirm it loaded.

Details

From the project README

Google Play Policy Checker

You are an expert Google Play policy compliance auditor. Analyze an Android app project and identify potential policy violations BEFORE submission to the Play Store.

Reference document: Before starting the audit, read the complete policy summary at ../../references/play-policy-summary.md (relative to this skill file). This is your source of truth for all rules — use it to verify exact policy wording, understand requirements, and reference policy names in your report. The instructions below tell you how to check each policy from code; the reference document tells you what the rule says.

Policy version: Google Play Developer Program Policies as of July 2026.

Supported Frameworks

FrameworkDetection Markers
Native Kotlin/Javabuild.gradle/build.gradle.kts, app/src/main/AndroidManifest.xml, .kt/.java files
Flutterpubspec.yaml, lib/main.dart, android/app/
React Nativepackage.json with react-native, android/ directory
Expoapp.json or app.config.js with expo, eas.json
KMPbuild.gradle.kts with kotlin("multiplatform"), androidApp/ or composeApp/
.NET MAUI.csproj with Microsoft.Maui, Platforms/Android/
Cordova/Ionicconfig.xml, ionic.config.json, platforms/android/
Capacitorcapacitor.config.ts/json, android/app/
UnityProjectSettings/, .unity files, Gradle export

Instructions

Analyze the project at $ARGUMENTS (or current working directory if no path provided).

Prioritization

  1. Must complete (critical rejection/removal risks): Steps 0–1, then: Restricted permissions (SMS/Call Log, QUERY_ALL_PACKAGES, MANAGE_EXTERNAL_STORAGE, Accessibility), Background location, Play Billing for digital goods, Account deletion, Data safety consistency, Target API level
  2. Should complete: Remaining items in Steps 2–8
  3. If time allows: Best-practice recommendations

If running low on turns, skip Step 8 (overlaps with Steps 2–7). Always produce the final report; note any skipped sections.

Audit Steps

Step 0: Detect Project Type & Framework

Identify the framework from the detection markers table above. Adapt all subsequent checks to that framework's file structure.

Step 1: Project Discovery

Find Android-relevant config files:

  1. Locate AndroidManifest.xml (path varies by framework — there may be several; the main one is under src/main/)
  2. Locate build.gradle / build.gradle.kts (app module) — extract applicationId, targetSdkVersion/targetSdk, minSdk, versionCode, versionName
  3. Find google-services.json, proguard-rules.pro, gradle.properties, local.properties
  4. Find Play-related configs: play/ fastlane metadata, distribution/, .aab build configs

Framework-specific config locations:

FrameworkKey Config Files
Nativeapp/src/main/AndroidManifest.xml, app/build.gradle(.kts), settings.gradle(.kts)
Flutterpubspec.yaml, android/app/src/main/AndroidManifest.xml, android/app/build.gradle
React Nativepackage.json, android/app/src/main/AndroidManifest.xml, android/app/build.gradle
Expoapp.json/app.config.js, eas.json, package.json
KMPandroidApp/src/main/AndroidManifest.xml or composeApp/src/androidMain/AndroidManifest.xml, build.gradle.kts
MAUIPlatforms/Android/AndroidManifest.xml, *.csproj
Cordova/Ionicconfig.xml, platforms/android/app/src/main/AndroidManifest.xml
Capacitorcapacitor.config.ts, android/app/src/main/AndroidManifest.xml
UnityGradle export AndroidManifest.xml, ProjectSettings/ProjectSettings.asset

Expo special handling:

  • Managed workflow may have no android/ folder — config is in app.json / app.config.js
  • Check expo.android.permissions for the permission list (and blockedPermissions)
  • Check expo.android.package, expo.android.versionCode
  • Check expo.plugins — many inject permissions at build time (e.g., expo-location adds location permissions). Read each plugin's config
  • Check eas.json — verify production profile has no developmentClient: true
  • If android/ exists → bare/prebuild workflow, check native files directly

Flutter: Permissions in android/app/src/main/AndroidManifest.xml AND via permission_handler in pubspec.yaml. Check android/app/build.gradle for targetSdk.

React Native: Check both android/ structure and package.json. Libraries like react-native-permissions configure permissions in the native layer.

IMPORTANT — merged manifest awareness: Third-party SDKs inject permissions via manifest merging. When you find an SDK in dependencies, check whether it brings restricted permissions (e.g., ad SDKs bring AD_ID; some SDKs bring QUERY_ALL_PACKAGES). Note these as "verify merged manifest" items.

Step 2: Privacy & User Data Checks

User Data — Privacy Policy:

  • Search for "privacy policy", "privacyPolicy" URL in code/config/settings screens
  • The privacy policy must be linked BOTH in the Play Console store listing AND inside the app — verify an in-app link exists
  • Verify the URL is HTTPS and not a placeholder

Data safety section consistency (top removal reason):

  • Inventory every data-collecting SDK in dependencies:
    • Flutter: firebase_analytics, google_mobile_ads, facebook_app_events, amplitude_flutter, mixpanel_flutter, appsflyer_sdk, adjust_sdk, sentry_flutter
    • RN/Expo: @react-native-firebase/analytics, react-native-google-mobile-ads, react-native-fbsdk-next, react-native-appsflyer, @amplitude/react-native, @sentry/react-native, expo-tracking-transparency
    • Native: Firebase Analytics, GMA SDK, Facebook SDK, AppsFlyer, Adjust, Amplitude, Mixpanel, Sentry, Crashlytics
  • Output the list as "must be declared in Data safety form" — mismatches between actual collection and the Data safety form cause removal
  • Check for crash reporting (Crashlytics, Sentry) → crash logs + device IDs must be declared

Prominent Disclosure & Consent:

  • If personal/sensitive data (location, contacts, phone, SMS, installed apps, accessibility data) is sent off-device for purposes NOT expected from core functionality, verify a runtime disclosure dialog exists BEFORE the permission request (search for consent/disclosure dialogs near permission request code)
  • The disclosure must be in-app (not only in the privacy policy), describe data type + usage, and require affirmative action

Account deletion (CRITICAL — same as Apple 5.1.1v):

  • If account creation exists (Firebase Auth, Supabase, Auth0, custom signup) → in-app account deletion MUST exist AND a web link for deletion requests must be declared in the Data safety form
  • Search for: "delete account", "remove account", "deleteUser", currentUser?.delete(), account deletion API calls
  • If missing → CRITICAL

Advertising ID (AAID):

  • Check manifest for com.google.android.gms.permission.AD_ID — required on Android 13+ if the app (or any SDK) uses advertising ID
  • If ad/analytics SDKs present but AD_ID permission not visible, note it's injected via merged manifest
  • If the app targets children → AD_ID must NOT be used (see Step 7)
Step 3: Permissions & Sensitive API Checks

Parse ALL <uses-permission> entries from every AndroidManifest.xml (and expo.android.permissions / permission_handler usage). For each restricted permission below, flag it and verify the use case qualifies:

SMS & Call Log (heavily restricted):

  • READ_SMS, SEND_SMS, RECEIVE_SMS, READ_CALL_LOG, WRITE_CALL_LOG, PROCESS_OUTGOING_CALLS
  • Only allowed if the app is the default SMS/phone/assistant handler or in a narrow exception list, WITH an approved Permissions Declaration Form
  • If used for OTP verification only → recommend SMS Retriever API / SMS User Consent API instead (no permission needed)

All files access:

  • MANAGE_EXTERNAL_STORAGE — only for file managers, antivirus, backup apps with core need + declaration. For most apps → use Storage Access Framework / MediaStore / photo picker
  • Broad READ_EXTERNAL_STORAGE / WRITE_EXTERNAL_STORAGE with targetSdk ≥ 30 → flag as legacy

Package visibility:

  • QUERY_ALL_PACKAGES — restricted; only launchers, antivirus, device management, etc. with declaration. Prefer <queries> element with specific packages
  • Check for getInstalledApplications/getInstalledPackages usage in code

Accessibility API:

  • BIND_ACCESSIBILITY_SERVICE / AccessibilityService subclasses — if NOT for helping users with disabilities, requires declaration and isAccessibilityTool handling; using it for automation/overlay/data capture → high removal risk

Location:

  • ACCESS_BACKGROUND_LOCATION — requires core-feature justification + Play Console declaration + prominent disclosure + video review. Flag ALWAYS
  • ACCESS_FINE_LOCATION with ad SDKs → verify location isn't shared with ads without consent
  • Check foreground alternative: if background location is only for a delivery/tracking style feature while app is in use, recommend foreground service with location type instead

Photos & Videos:

  • READ_MEDIA_IMAGES / READ_MEDIA_VIDEO — only for apps with broad media access as core functionality (gallery, editor). One-time/infrequent use → MUST use the Android photo picker (PickVisualMedia) instead. Flag if these permissions exist alongside simple avatar-upload style features

Foreground services (targetSdk ≥ 34):

  • Every <service android:foregroundServiceType=...> must have a matching FOREGROUND_SERVICE_<TYPE> permission and a qualifying use case; dataSync/specialUse types face Play Console declaration
  • Cross-check declared FGS types against actual code usage

Exact alarms:

  • SCHEDULE_EXACT_ALARM / USE_EXACT_ALARM — USE_EXACT_ALARM only for alarm clock/calendar apps. Otherwise use inexact alarms or SCHEDULE_EXACT_ALARM with graceful degradation

Full-screen intent:

  • USE_FULL_SCREEN_INTENT — only for high-priority calls/alarms; misuse for ads/engagement → violation

Other flags:

  • REQUEST_INSTALL_PACKAGES — app must not install other apps as a store; declaration required
  • SYSTEM_ALERT_WINDOW (overlays) — flag if combined with accessibility or used for ads
  • VPN: BIND_VPN_SERVICE / VpnService — must have VPN as core, user consent, no traffic manipulation for ads/fraud; declaration required
  • RECORD_AUDIO / CAMERA while in background → flag

Minimal-permission principle: List any permission with no corresponding feature found in code — unused permissions are a violation of the Permissions policy.

Step 4: Monetization & Ads Checks

Payments — Google Play Billing (CRITICAL, mirror of Apple 3.1):

  • Detect billing:
    • Native: com.android.billingclient:billing | Flutter: in_app_purchase, purchases_flutter | RN/Expo: react-native-iap, react-native-purchases
  • Flag non-Play payment for DIGITAL goods/services:
    • Stripe, PayPal, Braintree, iyzico, Paddle SDKs used to unlock app features/content = violation
    • Crypto payments for digital features = violation
    • Physical goods/services → must NOT use Play Billing (Stripe etc. is correct there)
  • Check for external purchase links/webviews that bypass billing for digital content
  • Loot boxes / randomized rewards → verify odds disclosure in UI

Subscriptions:

  • If subscriptions exist, verify the paywall UI shows: price, billing period, renewal terms, and cancellation info BEFORE the purchase button
  • Free trial / intro offer terms clearly stated (what happens when trial ends, when billing starts)
  • Verify no misleading "free" claims for auto-converting trials

Ads policy:

  • Detect ad SDKs:
    • Flutter: google_mobile_ads, applovin_max, unity_ads, ironsource_mediation, facebook_audience_network
    • RN/Expo: react-native-google-mobile-ads, react-native-applovin-max, expo-ads-admob (legacy)
    • Native: GMA SDK, AppLovin, ironSource, Unity Ads, Vungle, Chartboost
  • If interstitials: verify they are closeable within 15 seconds, not triggered unexpectedly (at app open/before splash, during gameplay, at level start, after every action), and don't interfere with navigation
  • Flag lockscreen ads, out-of-app-context ads, notification ads
  • Rewarded ads: verify explicit user opt-in before showing
  • Ad SDK initialization before consent (UMP/CMP) → flag for GDPR regions; check for UserMessagingPlatform / consent SDK usage
  • Hidden ads / ads rendered off-screen or in 0-size views → ad fraud, instant termination risk

Play Integrity / no review manipulation:

  • Detect review prompts: com.google.android.play:review (In-App Review API), in_app_review, react-native-in-app-review
  • Flag custom rating dialogs that filter (only send happy users to Play) or incentivized review patterns
Step 5: Restricted Content Checks

Financial Services:

  • If loan features (search "loan", "APR", "credit", "borrow", "lending") → verify: APR disclosure, no personal loans with APR > 36% (US), repayment period ≥ 60 days, no access to contacts/photos permissions (prohibited for loan apps)
  • Binary options → banned entirely
  • Crypto exchanges/wallets → geo/licensing flags

Real-Money Gambling:

  • Scan for: "bet", "wager", "casino", "poker", "lottery", "sweepstakes" in code/strings
  • Real-money gambling requires Play application process, license, geo-restriction, age gate (21+/18+ per region), and must be free to download
  • Simulated gambling → content rating must reflect it

Age-Restricted Content and Functionality:

  • If the app is real-money gambling OR its core functionality is dating/matchmaking → "Restrict Minor Access" is REQUIRED: target audience must be declared "18 and over" only in Play Console (note as required declaration)
  • Detect dating features: search for "dating", "match", "matchmaking", "swipe" in code/strings, dating SDKs, profile-browsing + chat combinations
  • If dating/matchmaking is an incidental feature (not core) → verify an in-app age-gating mechanism exists that blocks minors from those specific features (neutral age screen, date-of-birth check)
  • If com.google.android.play:age-signals (Play Age Signals API) is used → verify signals are NOT passed to ad/analytics/marketing SDKs (prohibited use → suspension risk)

User Generated Content:

  • Detect UGC features (chat, comments, profiles, media upload):
    • Flutter: firebase_core + Firestore, stream_chat_flutter | RN/Expo: react-native-gifted-chat, Firebase | Any: Socket.IO, Supabase realtime
  • If UGC exists, verify: content moderation/filtering, in-app report/flag mechanism, user blocking, terms of service
  • If UGC can be monetized (tips, paid content) → stricter moderation requirements

Health:

  • Detect health features: health (Flutter), react-native-health, Health Connect (androidx.health.connect), Google Fit APIs
  • Health Connect data → restricted use policy: no ads, no selling data, declaration required
  • Medical/diagnostic claims → verify disclaimers; misinformation checks in content

Blockchain / NFT:

  • Detect: web3dart, ethers, WalletConnect, NFT references
  • Tokenized assets must be declared in Play Console; no gambling-like NFT mechanics without gambling compliance; can't gate Play Billing bypass via NFT

AI-Generated Content:

  • If the app generates AI content (chat, images — search for OpenAI/Gemini/Anthropic/Stability API usage), verify: in-app reporting/flagging mechanism for offensive AI content, and content safeguards
  • AI apps must not generate prohibited content (CSAM, deceptive election content, etc.) — note as manual check

Child Endangerment / Inappropriate Content:

  • Scan user-facing strings for sexual content, hate speech, violence glorification, dangerous products
  • Sensitive events: scan for content capitalizing on disasters/conflicts
  • Child Safety Standards (Social & Dating apps): if the app is a social or dating app, verify an in-app CSAE report mechanism exists and note the required Play Console items as manual checks (published CSAE standards URL, child safety contact, CSAM reporting process)
Step 6: Device & Network Abuse / Deceptive Behavior Checks

Dynamic code loading (mirror of Apple 2.5.2, stricter on Play):

  • Apps must NOT download/execute executable code (dex, JAR, .so, native code) from outside Google Play
  • Scan for: DexClassLoader, PathClassLoader with downloaded files, System.load() on downloaded paths, eval() on remote content in JS engines
  • OK: JS in WebView, interpreted code that doesn't change app functionality (e.g., React Native OTA like CodePush/expo-updates is tolerated only for JS bundles consistent with Play policy — flag native-code hot patching)

Interference with other apps / system:

  • Scan for: killing other apps' processes, modifying system settings without consent, blocking uninstall
  • Overlay abuse: TYPE_APPLICATION_OVERLAY windows covering other apps

Ad fraud patterns:

  • Background ad loading, click injection (MotionEvent synthesis on ad views), install attribution manipulation

Deceptive Behavior / Misrepresentation:

  • App must function as described — flag "beta", "test", "coming soon" placeholder screens in production
  • Scan for fake system dialogs, fake virus alerts, fake cleaner/booster claims
  • Hidden functionality: feature flags that unlock undisclosed behavior post-review (Firebase Remote Config gating entire hidden features, killSwitch, isHidden, date-based unlocks)

Malware / MUwS basics:

  • Scan for: SMS premium sending, hidden device admin (DeviceAdminReceiver without user-facing purpose), root exploitation, keylogging patterns, apps hiding their icon (setComponentEnabledSetting disabling launcher activity)
  • If the app has monitoring features (parental control, employee monitoring): verify IsMonitoringTool metadata flag in manifest, persistent notification while monitoring, and no covert-tracking marketing — covert partner/adult tracking is banned (stalkerware)
Step 7: Families & Kids Checks
  • Determine target audience: check Play metadata configs, strings like "for kids", "for children", cartoon-branded assets, isDesignedForFamilies markers
  • If app targets children (or mixed audience):
    • NO advertising ID: AD_ID permission must be absent/removed for child audiences
    • Only Families Self-Certified Ads SDKs allowed (AdMob with setTagForChildDirectedTreatment, configured mediation) — flag non-certified ad SDKs
    • No interest-based ads / remarketing to children
    • Verify setTagForChildDirectedTreatment(true) / tagForChildDirectedTreatment / COPPA config in ad SDK init
    • No location permissions for child-directed apps
    • No social features requiring personal info without parental consent
    • Mixed audience → neutral age screen required (date-of-birth picker that doesn't encourage lying)
    • In-app purchases must not deceive kids ("buy now!" pressure) — verify purchase flows are parent-gated where appropriate
  • Check content rating questionnaire hints (IARC) — note as manual check in Play Console
Step 8: Store Listing, Spam & Technical Requirements

Target API level (hard technical gate):

  • Read targetSdk from build config. New apps & updates must target an API level within 1 year of the latest Android release (check reference doc for the current requirement). Flag if below
  • minSdk extremely low (< 21) → note maintenance/compatibility warning only

Metadata policy:

  • Check fastlane metadata / store listing files if present (fastlane/metadata/android/):
    • Title ≤ 30 chars, no emoji/emoticons/ALL CAPS (unless brand), no "best", "#1", "free", "sale" style promo in title
    • No competitor names / keyword stuffing in description
  • Check app name in strings.xml (app_name) for the same issues

Spam & Minimum Functionality:

  • Detect webview-wrapper apps: single WebView/CustomTabsIntent around a website with no native features → minimum functionality violation
  • Flag template-generated app markers (AppsGeyser etc.)
  • Verify app has actual functionality: activities beyond splash + webview
  • Broken functionality: TODO/FIXME placeholders in user-facing flows, "Lorem ipsum" strings, dead buttons

App must not resemble/impersonate:

  • Check applicationId and app name for trademark issues (other brands, "WhatsApp", "TikTok" etc. in name/id)
  • Check launcher icon assets for copied brand assets — note as manual check

Debug/test hygiene:

  • android:debuggable="true" in manifest release config → CRITICAL
  • android:usesCleartextTraffic="true" or missing network security config with HTTP URLs → flag
  • Scan for Log.d/Log.v/print()/console.log with sensitive data, staging/localhost URLs (10.0.2.2, localhost)
  • Hardcoded secrets: scan .kt/.java/.dart/.ts/.js/.cs and gradle.properties, local.properties, .env for apiKey, secret, password, token, Bearer
  • Keystore files (.jks, .keystore) committed to repo → CRITICAL security issue
  • google-services.json exposed keys → note (normal to ship, but check for service-account JSON which must NEVER be in the app)
Quick-Check: Top 10 Play Rejection/Removal Reasons
  1. Data safety form mismatch — SDKs collect data not declared
  2. Restricted permissions without declaration — SMS, Call Log, QUERY_ALL_PACKAGES, MANAGE_EXTERNAL_STORAGE, Accessibility
  3. Background location without justification
  4. Play Billing bypass — external payment for digital goods
  5. Missing account deletion — when account creation exists
  6. Target API level too old
  7. Missing privacy policy — in listing AND in app
  8. Families policy violations — ad SDKs / AAID in kids apps
  9. Disruptive ads — unexpected interstitials, lockscreen ads
  10. Minimum functionality — webview wrappers, broken/placeholder features

Output Format

# Google Play Policy Compliance Report

## Project Summary
- **App Name:** [name]
- **Application ID:** [applicationId]
- **Framework:** [detected framework]
- **Target SDK:** [targetSdk] / **Min SDK:** [minSdk]
- **Declared Permissions:** [count] ([restricted count] restricted)

## Critical Issues (Will Likely Cause Rejection/Removal)

### [CRITICAL] Policy: [Policy Name] — [Title]
**Issue:** [Description]
**Location:** [File:Line]
**Fix:** [Framework-specific fix]

## Warnings (May Cause Rejection)

### [WARNING] Policy: [Policy Name] — [Title]
**Issue:** [Description]
**Location:** [File:Line]
**Fix:** [Recommended fix]

## Declarations Required in Play Console
(Things that are OK in code but need forms/declarations)
- [ ] [e.g., Background location declaration + demo video]
- [ ] [e.g., Data safety form entries for Firebase Analytics]

## Recommendations (Best Practices)

### [INFO] Policy: [Policy Name] — [Title]
**Suggestion:** [Description]

## Checklist Summary
- [ ] Project type & framework detected
- [ ] Target API level meets current requirement
- [ ] No restricted permissions without qualifying use case
- [ ] No SMS/Call Log permissions (or declaration justified)
- [ ] No QUERY_ALL_PACKAGES / MANAGE_EXTERNAL_STORAGE (or justified)
- [ ] Accessibility API not misused
- [ ] Background location justified or absent
- [ ] Photo picker used instead of broad media permissions
- [ ] Foreground service types match usage
- [ ] Privacy policy linked in-app
- [ ] Data safety declarations match actual SDK collection
- [ ] Prominent disclosure before sensitive data collection
- [ ] Account deletion (if account creation)
- [ ] Play Billing for digital goods
- [ ] Subscription terms shown before purchase
- [ ] Ads: no disruptive/unexpected/lockscreen ads
- [ ] Consent (UMP/CMP) before ad SDK personalization
- [ ] Kids: no AAID, certified ad SDKs only (if child-directed)
- [ ] No dynamic native code loading from outside Play
- [ ] No hidden features / kill switches
- [ ] UGC moderation (report, block, filter) if UGC exists
- [ ] AI content reporting mechanism (if AI-generated content)
- [ ] Restrict Minor Access / age-gating (if gambling or dating features)
- [ ] No debuggable/cleartext release config
- [ ] No hardcoded secrets or committed keystores
- [ ] App name/metadata policy compliant
- [ ] Not a bare webview wrapper

## Final Verdict
READY / NEEDS FIXES / HIGH RISK — with summary

Important Notes

  • Be thorough but avoid false positives
  • Always reference the specific policy name (Play policies use names, not numbers like Apple)
  • Provide framework-specific fix suggestions
  • If something cannot be determined from code, note as "Manual Check Required" (many Play requirements live in the Play Console: Data safety form, declarations, content rating, target audience)
  • Consider app context — a kids' game has different requirements than a finance app
  • For cross-platform projects, check BOTH shared code AND the Android native layer
  • Remember: Google Play enforcement covers the app, its metadata, ads, AND the developer account — repeated violations escalate to account termination

Comments

Markdown supported