TestFlight is Apple’s beta testing service. Every indie iOS app should run a TestFlight beta before submitting to the App Store — not because Apple requires it, but because it catches the bugs that will get you rejected.
Background
TestFlight lets you distribute pre-release builds to up to 100 internal testers (no review) and up to 10,000 external testers (after a quick review). For indie developers the real value is twofold: first, it forces you to ship a TestFlight build that goes through Apple’s tooling, surfacing IAP, signing, and provisioning bugs early; second, it gets your app onto real devices with real users in real conditions before the App Review reviewer touches it.
How to tell
- You have a working app build that compiles and runs on at least your own device.
- You are within 1-3 weeks of submitting to the App Store.
- You have at least 3-5 people who would actually use the app.
- You have some way to collect feedback (email, Discord, a form — anything).
Step by step
-
Archive + upload. In Xcode:
1. Set device target: Any iOS Device (arm64) — not a simulator 2. Product → Archive (5-15 min) 3. Organizer pops up → "Distribute App" → "App Store Connect" → "Upload" 4. Signing: Automatically manage signing (unless your org uses manual certs) 5. Wait for upload (10-30 min, depends on size and bandwidth)CLI alternative (skip the Xcode UI):
# Archive xcodebuild -workspace MyApp.xcworkspace -scheme MyApp \ -configuration Release -archivePath build/MyApp.xcarchive archive # Export ipa xcodebuild -exportArchive -archivePath build/MyApp.xcarchive \ -exportOptionsPlist ExportOptions.plist -exportPath build/ # Upload to App Store Connect xcrun altool --upload-app -f build/MyApp.ipa \ -u "your-apple-id@example.com" -p "@keychain:AC_PASSWORD"Common upload failures: bundle ID mismatch with App Store Connect / missing push notification entitlement / Info.plist missing NSLocationWhenInUseUsageDescription.
-
Wait for processing. App Store Connect → TestFlight → Builds:
Uploading in progress Processing Apple processes (5-30 min) Ready to Test ← ready Invalid Binary ← failed, check email Missing Compliance ← encryption answer missing, fill in the build detail“Missing Compliance”: 99% pick “No, encryption used is exempt” (plain HTTPS is exempt).
-
Configure Internal Testing: up to 100 team members, no review:
App Store Connect → TestFlight → Internal Testing → "+" - Group Name: Internal QA - Test Information: - Beta App Description: focus of this test - Email: your feedback inbox - Add Testers: pick Account Holder + Developer-role members - Enable for Build: select your build → SaveInvites land in their TestFlight app immediately. Free Apple IDs can’t test IAPs — team must use sandbox accounts.
-
Configure External Testing: up to 10,000 invitees, first new build goes through Beta App Review (~24h, often ≤8h):
App Store Connect → TestFlight → External Testing → "+" - Group Name: Public Beta (or specific cohort like "Power Users") - Add Testers: type emails, CSV import, or enable Public Link - Build to test: select build - Submit for Beta App Review: - Beta App Description: ≤4000 char (can reuse App Store description) - What to Test: focus of this version (see step 5) - Demo account: if login required - Notes: anything the reviewer needs to know -
Write “What to Test”: not “test everything”, but 3-5 specific items:
Bad: "Please test the new version" Good: Focus this build: 1. New onboarding flow (first 60s): can a fresh user complete a ritual without any guidance? 2. iPad landscape layout: does the 21-day calendar still display fully after rotating? 3. Family Sharing: when sharing with family members, do push notifications arrive within 30s? 4. Memory: after 30 minutes of continuous use, does the app slow down or get killed? Do NOT test: - Settings page (unchanged from previous build) - Detailed charts (known bug, fixed in v1.1.1) -
Use Public Link sparingly. Enable: External Testing group detail → “Enable Public Link”.
Upside: anyone with the link can install (up to 10,000) Downside: - Once full, you can only disable the entire group - Can be scraped by bots filling slots - No identity → low-quality feedback Recommended: private invites + Discord-collected emails → manually add to External Testers -
Feedback channels. Run one of each, pointed at different scenarios:
TestFlight built-in feedback: Tester screenshots + "Send to Developer" — includes device / OS / build metadata View at App Store Connect → TestFlight → Feedback Email: Put beta@yourdomain.com in "What to Test"; lets testers paste stack traces inline Discord / Slack channel: Long-term beta tester community; @everyone each new build Auto crash reporting: Wire up Sentry / Crashlytics for TestFlight builds View at App Store Connect → TestFlight → Crashes (Sentry's realtime view is usually better) -
Cadence: 2-5 days per build during active beta. Stagnant betas die — testers forget the app exists.
Suggested cadence: D0 First build D2 Patch obvious bugs, ship v1.0.1 D5 Small feature iteration + second wave fixes, ship v1.0.2 D7 Full sweep, prepare for App ReviewEach new build push triggers a TestFlight push notification to all testers with the What’s New.
-
Last TestFlight build before App Review. Use the exact metadata you plan to submit (screenshots, keywords, description, privacy answers) — run it through External:
Purpose: - Have 5-10 real users live with the near-final experience for 24h - Catch last-mile issues: icon mush on certain devices / IAP sandbox-to-production transition / push token registration failing in Production environment Only then promote the same build to App Review via "Add for Review".
Common pitfalls
- Treating TestFlight as a marketing channel. It is not. Users on TestFlight are testers, not customers, and they will not convert at launch.
- Adding “test123” type accounts that are not real users. They produce useless feedback.
- Letting builds expire. TestFlight builds expire after 90 days; if your beta runs longer, you must ship a new build.
- Not testing IAP in the sandbox. TestFlight uses sandbox StoreKit, not production — test purchases must be done as sandbox users.
- Forgetting to include the beta tester list in the description for Beta App Review. Apple does check.
- Adding crash logging at the last minute. Wire up Sentry, Crashlytics, or similar before beta starts — otherwise crash reports are useless.
Who this is for
Any indie iOS developer about to launch their first app, or one launching a major version update.
When to skip this
Apps so simple that a 30-minute self-test catches everything — though those are rarer than you think.
FAQ
- How many testers should I have?: 5-15 active testers is usually enough for an indie app. More testers means more feedback to process, not better feedback.
- How long should a beta run?: 1-3 weeks for most indie apps. Less than a week is too short to find non-obvious bugs; more than a month and motivation drops.
- Will TestFlight install on a tester’s iPhone over the App Store version?: TestFlight installs alongside the App Store version with a slight icon difference. They do not conflict.
- Can testers leave reviews on the App Store?: Not from the TestFlight build itself. They would need to install the App Store version after launch and review separately.
Related
- What an Indie Developer Should Prepare Before Launching on the App Store
- In-App Purchases via RevenueCat — a 30-Minute Intro
- After Launch — How to Iterate on Your App Store App Without Panic
Tags: #Indie dev #App Store #TestFlight #App launch #Getting started