Originally published on jahanzaibramzan.com.
Most app launches that go badly don't fail because the product is bad. They fail on the boring stuff: a rejected build two days before the announcement, a crash on one Android manufacturer that nobody tested, a login flow that breaks the moment a real user opens the app from a push notification. After shipping releases to both stores for years — from solo side projects to an app with hundreds of thousands of users — this is the checklist I run before anything goes live.
Start the store work six weeks out, not six days
Apple and Google both have review processes, both have paperwork, and both can say no. The earlier you touch them, the less they can hurt you.
App Store Connect and Play Console accounts. Set these up as soon as you have a name. Apple's developer program enrolment for a company can take a couple of weeks if D-U-N-S verification is involved. Google's account verification has its own delays, and new developer accounts now need a closed test with real testers before they can publish to production.
Bundle ID and package name. Decide them once. They're permanent, and they show up in deep links, Firebase configs, and every store URL.
Privacy policy and data disclosures. Both stores require a hosted privacy policy URL and a data-safety / privacy-nutrition form describing what you collect. If you use Firebase Analytics, Crashlytics, or any SDK that touches the ad ID, say so. Mismatches between the form and what the app actually does are a common rejection reason.
Age rating, content, and permissions. Fill the questionnaires honestly, and make sure every permission the app requests has a visible reason in the UI. iOS reviewers reject apps that ask for camera or location access with a vague purpose string.
Make the build reproducible
If building a release involves someone's laptop and a series of remembered steps, it will break on the day you need it. Automate it.
I use Fastlane for both platforms, with lanes that bump the build number, build, sign, and upload:
# fastlane/Fastfile
platform :ios do
lane :release do
increment_build_number(xcodeproj: "ios/MyApp.xcodeproj")
match(type: "appstore", readonly: true)
build_app(workspace: "ios/MyApp.xcworkspace", scheme: "MyApp")
upload_to_testflight(skip_waiting_for_build_processing: true)
end
end
platform :android do
lane :release do
gradle(task: "bundle", build_type: "Release", project_dir: "android/")
upload_to_play_store(track: "internal", aab: lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH])
end
end
Signing is the part that bites. Use Fastlane match (or a similar shared store) for iOS certificates so the whole team can build. On Android, enrol in Play App Signing and keep the upload key somewhere you can't lose it — a lost upload key is a support ticket, a lost legacy signing key is a new app listing.
If you're on Expo, EAS Build and EAS Submit cover the same ground with less setup. Either way, the release should be one command.
Test on real devices, including bad ones
Simulators lie. They have unlimited memory, perfect networks, and no manufacturer quirks. Before a launch, the build needs time on physical hardware.
The minimum I want in hand: one recent iPhone, one older iPhone still on a supported iOS, one flagship Android, and one cheap Android with 3–4 GB of RAM — ideally a Samsung or Xiaomi, because their Android skins are where the surprising bugs live (aggressive background killing, notification channels, and permission dialogs that behave differently).
Test the flows that only exist in production: opening the app from a push notification when it's cold, from a deep link when it's backgrounded, after the OS kills it and restores state, and on a slow network with airplane mode toggled mid-request. Log in with a brand-new account, not your dev account with 200 test records.
Ship to testers before you ship to everyone
Both stores give you free staged distribution. Use all of it.
- TestFlight for iOS: internal testers immediately, external testers after a lighter review. Get at least a week of real usage.
- Play internal → closed → open testing: same idea. Open testing also lets you gather pre-launch reviews that don't count against your production rating.
Ask testers for specific things — "install, log in, complete one core task, kill the app, reopen" — not "let me know what you think." You'll get bug reports instead of opinions.
Have monitoring on before the first install
If you don't have crash reporting when you launch, you'll find out about crashes from one-star reviews. Crashlytics is free and takes an hour to add to a React Native app; Sentry is a good alternative and handles JS errors more gracefully.
Set up, at minimum:
- Crash reporting with source maps uploaded so JS stack traces are readable.
- Analytics for the handful of events that define success: first open, sign-up completed, core action completed, day-2 return.
- Alerting on crash-free rate dropping below a threshold, so you hear about a bad release in hours, not days.
Check that you can actually see events from a TestFlight build before launch day. Dashboards that show nothing are a common surprise.
Roll out gradually
You don't have to release to 100% of users at once, and you shouldn't.
On Google Play, staged rollout lets you release to 5%, then 20%, then 50%, then everyone, halting if crash rates spike. On the App Store, phased release does the same over seven days for automatic updates. Turn both on for every release, not just the first.
Pair that with a remote kill switch: a Remote Config flag or a tiny Firestore document the app reads at startup that can disable a feature or show a "please update" screen. When something goes wrong at 3 a.m., turning off one feature is much better than waiting a day for a review.
Write the store listing for humans, not for you
The listing gets you the install; the app has to earn the second open. A few things that consistently help:
- The first screenshot is the one that matters. Show the core outcome, with a short caption, not a login screen.
- The first two lines of the description are visible before "more". Say what the app does and who it's for in plain language.
- Use the subtitle (iOS) and short description (Android) for the main keyword phrase you want to be found for.
- Localise the listing for the two or three languages where you expect most users. Machine translation of the listing is acceptable; of the app itself, less so.
Plan the first week, not just the first day
Launch day is the start of the work. Block out the week for it:
- Someone watching Crashlytics and reviews daily, with the ability to ship a hotfix within 24 hours.
- Reply to reviews, especially the negative ones. Public replies affect conversion.
- Look at the funnel from first open to core action. If 60% drop off at sign-up, that's the next release.
- Hold back at least one meaningful improvement so version 1.1 has something to say two weeks later.
The checklist
- Store accounts, bundle IDs, privacy policy, data forms, age ratings: done six weeks out.
- Release build is one command; signing is shared and backed up.
- Tested on real devices, including a cheap Android; production-only flows covered.
- TestFlight / Play testing tracks used for at least a week.
- Crash reporting, analytics, and alerts verified working before launch.
- Staged rollout on, kill switch in place.
- Listing written for users, first screenshot shows the outcome.
- First-week plan: monitoring, reviews, hotfix capacity, a 1.1 in the pipeline.
None of this is glamorous, and all of it is the difference between a launch that builds momentum and one that spends its first week apologising. If you'd like help getting a React Native app across the line — release engineering, store submission, or a pre-launch audit — see Services or get in touch.
Top comments (0)