TestFlight Automatic Build Distribution Setup
Manual upload via Xcode Organizer causes pain in any iOS team. Forgotten bitcode flag, outdated certificate only on one developer's MacBook, Upload Error 409 with no explanation—all block build delivery to testers for hours. Automatic TestFlight upload via altool or Fastlane removes the human from the chain.
Code Signing Challenge in CI
Main technical barrier—Code Signing. In Xcode Organizer it "just works" because Xcode grabs certificate and provisioning profile from macOS keychain. In CI, no such keychain exists. Without setup:
error: exportArchive: No signing certificate "iOS Distribution" found
Two options: Fastlane match (recommended for teams) or sigh + cert (single project). match stores certificates and profiles in encrypted Git repository, CI clones it before build and imports into temporary keychain. No manual file passing.
How Automatic Upload Works
altool (legacy, but working) and xcrun altool --upload-app require App Store Connect API Key. Apple now recommends xcrun notarytool for macOS and altool for iOS, but practically, Fastlane pilot (deliver for metadata) is more reliable—handles errors and retries.
Typical Fastfile for TestFlight:
platform :ios do
lane :beta do
setup_ci # configures temporary keychain in CI
match(
type: "appstore",
readonly: true,
git_url: ENV["MATCH_GIT_URL"],
password: ENV["MATCH_PASSWORD"]
)
increment_build_number(
build_number: ENV["CI_BUILD_NUMBER"] || Time.now.to_i.to_s
)
build_app(
scheme: "MyApp",
configuration: "Release",
export_method: "app-store"
)
upload_to_testflight(
api_key_path: "fastlane/api_key.json",
skip_waiting_for_build_processing: true,
changelog: ENV["CHANGELOG"] || "Automated build"
)
end
end
skip_waiting_for_build_processing: true is important—without it Fastlane blocks 10–20 minutes while Apple processes build. In CI this wastes agent slot.
App Store Connect API Key
Apple removed password login support (App-Specific Password) for altool end of 2023. Now API Key is mandatory. Create in App Store Connect → Users and Access → Integrations. Need App Manager role minimum. Key (AuthKey_XXXXXX.p8) stored in CI secrets, path passed via api_key_path or via APP_STORE_CONNECT_API_KEY_KEY_ID, APP_STORE_CONNECT_API_KEY_ISSUER_ID, APP_STORE_CONNECT_API_KEY_KEY environment variables.
Tester groups in TestFlight added automatically: groups: ["Internal Testers", "QA Team"] in upload_to_testflight. External testers require beta review—Apple limitation, not automatable.
Build Number Increment
TestFlight rejects builds with same CFBundleVersion as already uploaded. Standard approach—use CI build number: CI_BUILD_NUMBER in GitHub Actions, $CI_PIPELINE_IID in GitLab, $BITRISE_BUILD_NUMBER in Bitrise. Or git rev-list --count HEAD as monotonically increasing number.
Process
Setup App Store Connect API Key → configure match for CI → write Fastfile → test on real CI agent with macOS → setup tester groups → document.
Timeline: 1–3 days depending on whether match is configured or needs setup from scratch. Cost calculated individually.







