TestFlight Expert
SKILL.md
TestFlight Expert
Distribute beta builds and collect feedback through Apple's TestFlight.
TestFlight Overview
- Internal Testing: Up to 100 testers (no review)
- External Testing: Up to 10,000 testers (requires review)
- Build Expiry: 90 days
- Feedback: Screenshots and crash reports
Fastlane Upload
Basic Upload
# Fastfile
lane :beta do
build_app(scheme: "App")
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end
With Changelog
lane :beta do
build_app(scheme: "App")
upload_to_testflight(
changelog: "Bug fixes and improvements",
distribute_external: true,
groups: ["Beta Testers"]
)
end
App Store Connect API
Setup
# Create API key in App Store Connect
# Users and Access → Keys → App Store Connect API
# Store credentials
export APP_STORE_CONNECT_API_KEY_ID="XXXXXXXXXX"
export APP_STORE_CONNECT_ISSUER_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export APP_STORE_CONNECT_API_KEY_PATH="~/.appstore/AuthKey.p8"
Fastlane Config
# Appfile
app_store_connect_api_key(
key_id: ENV["APP_STORE_CONNECT_API_KEY_ID"],
issuer_id: ENV["APP_STORE_CONNECT_ISSUER_ID"],
key_filepath: ENV["APP_STORE_CONNECT_API_KEY_PATH"]
)
Managing Testers
Add Internal Tester
# Must be App Store Connect user
# Add manually in App Store Connect
Add External Group
lane :add_testers do
upload_to_testflight(
groups: ["Beta Testers", "VIP Testers"],
distribute_external: true
)
end
CLI Tester Management
# Using app-store-connect-cli
asc testflight add-tester \
--email "tester@example.com" \
--group "Beta Testers" \
--app-id 123456789
CI/CD Integration
GitHub Actions
name: TestFlight
on:
push:
branches: [main]
jobs:
testflight:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- name: Setup Signing
uses: apple-actions/import-codesign-certs@v2
with:
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
p12-password: ${{ secrets.CERTIFICATES_PASSWORD }}
- name: Build & Upload
run: |
bundle exec fastlane beta
env:
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }}
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.ASC_KEY }}
Build Processing
Wait for Processing
lane :beta do
build_app(scheme: "App")
upload_to_testflight(
skip_waiting_for_build_processing: false,
wait_processing_timeout_duration: 3600
)
# Build is ready for testing
end
Skip Waiting
lane :beta do
build_app(scheme: "App")
upload_to_testflight(
skip_waiting_for_build_processing: true
)
# Continue without waiting (faster CI)
end
Beta Review Tips
What Gets Reviewed
- First build of new app
- Major version changes
- Significant feature additions
Speed Up Review
- Complete app description
- Add test account credentials
- Clear beta release notes
- No placeholder content
Typical Review Time
- 24-48 hours for external builds
- Internal builds: No review needed
Collecting Feedback
In-App Feedback
import StoreKit
// Prompt for beta feedback
SKStoreReviewController.requestReview()
TestFlight Feedback
- Users shake device to send feedback
- Includes screenshot + notes
- Crash reports auto-collected
Version Management
lane :beta do
# Auto-increment build number
increment_build_number(
build_number: latest_testflight_build_number + 1
)
build_app(scheme: "App")
upload_to_testflight
end
Use when: Beta distribution, tester management, CI upload automation