TestFlight external testers: setup, limits and troubleshooting
To add TestFlight external testers, create an external group in the TestFlight tab of App Store Connect, add a processed build, and invite up to 10,000 people by email or public link. The first build you submit goes through a full TestFlight App Review; later builds of the same version may not need one.
Internal testers skip that review. Up to 100 App Store Connect users on your team can install a build as soon as it's processed, cleared for export compliance and added to their group. Every build expires 90 days after upload. When testers say TestFlight shows no builds, the cause is usually one of these: missing compliance, a build that was never added to their group, a build still in review or never released to testers, an expired build, or a device that can't run it.
By Redjan Hysa, founder of MetaRun · Facts checked October 12, 2026
- external testers per app
- 10,000
- internal testers, all App Store Connect users
- 100
- a build stays testable after upload
- 90 days
- builds you can submit to TestFlight App Review
- 6 per 24 h
- devices one tester can install a beta on
- 30
- minimum iOS or iPadOS for the TestFlight app
- iOS 16
Reference tables
| Detail | Internal testers | External testers |
|---|---|---|
| Who | App Store Connect users with the Account Holder, Admin, App Manager, Developer or Marketing role | Anyone, invited by email or through a public link |
| Limit | 100 | 10,000 per app |
| Review | None | TestFlight App Review on the first build; later builds of a version might skip the full review |
| New builds | Optional automatic distribution per group (Xcode Cloud builds are always added by hand) | Added to the group one at a time |
| TestFlight Internal Only builds | Allowed | Not allowed |
| What you see | Name and email | Name and email for email invites; Anonymous for public link testers |
| Status | What it means | What to do |
|---|---|---|
| Missing Compliance | No export compliance answer yet. Nobody can test it. | Answer the encryption questions on the build. |
| Waiting for Export Compliance Review, In Compliance Review | Your encryption documentation is with Apple. | Wait. |
| Ready to Submit | Internal testers can use it; external testing needs review. | Add it to an external group and submit for review. |
| Waiting for Review, In Beta Review | TestFlight App Review has it. | Wait. External testers can't install yet. |
| Ready to Test | Testable, but no testers have it (or you chose to notify them manually). | Add a group, or click Notify Testers. |
| Testing | At least one group or tester has it. | Nothing. |
| Rejected | TestFlight App Review rejected it; it can't be used in TestFlight. | Read the details in App Review, fix, upload a new build. |
| Expired | Past its 90-day window, or expired by you. | Upload a new build. |
| Not Available for Testing | The provisioning profile is missing an application identifier. | Upload a new build with a correct profile. |
| Invalid Binary | The upload didn't meet requirements. | Fix the issues and upload again. |
Apple's App build statuses reference.
How to add external testers in TestFlight
You need the Account Holder, Admin or App Manager role. The example sends build 312 of version 2.4 to a group called Beta Club.
- 01
Fill in Test Information
In the TestFlight tab, under Additional, click Test Information. The Beta App Description is required, and the Feedback Email is where testers reach you. Fill in the Beta App Review contact and, if the app needs a login, a sign-in account.
- 02
Clear export compliance
Under Builds, click the platform, then build 312. If it says Missing Compliance, click Provide Export Compliance Information and answer the questions.
- 03
Create the external group
Click the add button (+) next to External Testing, name the group Beta Club, and click Create. App Store Connect requires an internal group to exist first.
- 04
Add the build and What to Test
In the group, click Add Builds, choose the platform, version 2.4 and build 312. Write What to Test (localized versions are optional), decide whether to tick Automatically notify testers, then click Submit Review, or Start Testing if the build is already approved.
- 05
Invite testers
Click the add button (+) next to Testers to add people by email, pick existing testers or import a CSV. Or click Create Public Link under the group's testers. If you left notification off, go to the build row after approval and click Notify Testers.
TestFlight beta app review: what to expect
Adding a build to an external group submits it to TestFlight App Review. Apple reviews the build and its test information; the first build gets a full review and later builds of the same version might not. Only one build per version can be in review at a time, and you can submit up to six builds in 24 hours. Apple doesn't publish a turnaround for beta review (its 24 and 48 hour goals are stated for App Review submissions), so leave a margin before a beta deadline.
On approval, Admins get an email. On rejection the build shows Rejected and can't be used in TestFlight again; the details are in App Review under General in the sidebar, and you appeal by contacting TestFlight App Review. Treat the beta sign-in account like the one you give App Review: it has to work, and it mustn't expire mid-review.
TestFlight public links and tester criteria
A public link is either Open to Anyone or Filter by Criteria, where you pick devices and OS ranges and only matching testers can accept. Set Limit caps how many people can join through the link, anywhere from 1 to 10,000. Anyone can forward the link, and testers who join through it show up as Anonymous, though you still see installs, sessions and crashes.
The group's insight cards warn when no build is compatible with your criteria, when the link is full, or when a build is about to expire. Public link metrics (views, accepted, didn't meet criteria, didn't accept) cover 30 days. When you hit your limit, disable the link so people trying to join can see the beta isn't taking new testers.
Build expiry, What to Test and tester devices
Each build is testable for 90 days from upload, and testers see the days left in TestFlight. Expire Build stops installs early. If you don't expire it, testers keep access even after that build goes live on the App Store. Removing a build from a group doesn't pull it from testers already using it.
What to Test belongs to the build, not the group: everyone with access sees the same text. Write what changed and where to look, for example "New export flow under Settings > Data; try it with 500+ items". Testers need the TestFlight app (iOS or iPadOS 16, macOS 13, tvOS 18, visionOS 1 or watchOS 9 or later) and a device that meets your build's minimum OS. The beta replaces any App Store copy, in-app purchases are free, and subscriptions renew daily, up to six times a week.
Common problems and how to fix them
TestFlight shows no builds available, and the build says Missing Compliance
Why: The build has no export compliance answer. Until it does, nobody can test it, internal testers included.
Fix: Open the build in the TestFlight tab and click Provide Export Compliance Information. Add ITSAppUsesNonExemptEncryption to Info.plist so future builds arrive answered.
TestFlight shows no builds available to a tester, but the build is processed
Why: Testers only see builds added to their group or to them individually. For external groups, the build may still be waiting for review, or it was approved with Automatically notify testers off (status Ready to Test).
Fix: Check the Groups column next to the build and add the tester's group. If the status is Ready to Test, click Notify Testers. Xcode Cloud builds always need adding by hand.
TestFlight build expired
Why: Builds stop working 90 days after upload, or earlier if someone clicked Expire Build.
Fix: Upload a new build and add it to the groups. Upload a fresh build every couple of months to keep long-running betas alive.
Build not visible in TestFlight after upload
Why: It's still processing, or it ended as Invalid Binary or Not Available for Testing (a provisioning profile without an application identifier).
Fix: Wait for Apple's processing email; past 24 hours, contact Apple. Fix the reported errors and upload again; a failed upload can reuse its build number.
TestFlight not receiving the invite email
Why: Internal testers get the email only once their group has a testable build. External testers are notified after approval, and only automatically if Automatically notify testers was ticked. Spam filters catch the rest.
Fix: Give the group a testable build first. In Testers, select those still Invited and choose Reinvite. Or send a public link instead.
TestFlight external testers stuck in Waiting for Review
Why: The build is in TestFlight App Review, which checks the build and its test information, so a missing description or a sign-in that doesn't work can get it rejected. A second build of the same version can't enter review until the first is done.
Fix: Complete Test Information while you wait. Don't upload new builds to restart the clock; you can only have one build per version in review.
Testers can't install the build
Why: Their device runs an OS below the build's minimum or below what the TestFlight app needs, the build is for a different platform, they don't meet the public link criteria, or they already use 30 devices. Managed Apple Accounts in reserved domains can't test at all.
Fix: Ask for the device model and OS version. TestFlight only shows Install when a compatible build exists, so lower the deployment target or adjust the criteria if needed.
TestFlight public link full
Why: The link reached the limit you set, or the app reached 10,000 external testers.
Fix: Raise the limit under Manage next to Public Link, or remove inactive testers: filter Testers by sessions, select those with none, and delete them.
Do it from Claude Code, Codex, Cursor or Xcode with MetaRun
TestFlight work comes in small pieces at awkward times: a build finishes processing while you're in the middle of something, someone has to add it to the right groups, the What to Test field is empty again, and tester feedback sits in a separate tab.
Your agent can do each piece through MetaRun, in the same session where the build was made. Crash feedback and screenshots from testers come back as data the agent can match against your code.
Before you start
- A build uploaded from Xcode, Xcode Cloud, fastlane or CI.
- Tester groups set up in App Store Connect.
- An answer for export compliance, or ITSAppUsesNonExemptEncryption in Info.plist.
How the agent runs it
- 01
Wait for processing
Your agent reads the build list and reports when the build is processed. A build still processing can't be assigned.
- 02
Clear export compliance
If the build has no encryption answer, the agent previews the declaration, or reuses an existing one.
- 03
Assign and describe
Each group assignment and the What to Test text is its own preview.
- 04
Read what testers found
Crash feedback, crash logs and screenshot feedback come back as structured data, ready to compare with the code.
An example session
When build 312 finishes processing, give it to Internal and Beta Club, with What to Test written from the commits since build 309.
- apple_list_buildsBuild 312 processed. No export compliance answer yet.
- apple_preview_declare_build_encryptionPreview: exempt encryption, assigned to build 312. Not revertible.
- Your agent asks before running apple_apply_declare_build_encryption. You read the preview above and approve.
- apple_apply_declare_build_encryptionDeclared.
- apple_preview_assign_build_to_groupPreview: build 312 to the Beta Club group.
- Your agent asks before running apple_apply_assign_build_to_group. You read the preview above and approve.
- apple_apply_assign_build_to_groupAssigned to Beta Club.
- apple_preview_set_what_to_testPreview: What to Test in English, from the commits since build 309.
Illustrative: your apps, versions and numbers will differ. The tool names and their order are real.
The MetaRun tools involved
| Tool | What it does |
|---|---|
| apple_list_buildsread | Builds with version, build number, processing state and expiry. |
| apple_list_testflight_groupsread | Internal and external tester groups. |
| apple_preview_assign_build_to_grouppreview + apply | Give a build to a tester group. |
| apple_preview_set_what_to_testpreview + apply | What to Test notes for a build, per language. |
| apple_preview_declare_build_encryptionpreview + apply | Answer export compliance so the build can be tested. |
| apple_list_testflight_crash_feedbackread | Crash reports testers submitted, with their comments. |
| apple_get_crash_logread | The crash log behind a tester's report. |
| apple_list_testflight_screenshot_feedbackread | Screenshots and comments testers sent from the app. |
| apple_preview_expire_buildpreview + apply | Stop testing a build before its 90 days are up. |
Each preview has an apply twin that only runs with the confirm token from a fresh preview, and refuses if App Store Connect changed in between.
What Apple enforces along the way
Builds expire after 90 days
A TestFlight build stops working 90 days after upload. Expiring one early is a preview and apply like any other change.
External testing needs Beta App Review
The first build of a version sent to external testers goes through Beta App Review. Internal testers get it as soon as it's processed.
Export compliance can't be undone
Declaring a build's encryption is permanent for that build, so the preview says it's not revertible. Setting ITSAppUsesNonExemptEncryption in Info.plist answers it at upload instead.
MetaRun doesn't upload builds
Xcode, Xcode Cloud, fastlane or your CI uploads the build. MetaRun takes over once it's in App Store Connect.
Set up your agent
Connect once, then ask in plain words. Pick your agent:
Claude Code Anthropic
Run claude mcp add --transport http --scope user metarun https://metarun.dev/api/mcp, then run /mcp in Claude Code and sign in to MetaRun in your browser.
01 · Add the server
Run it in any terminal. --scope user makes MetaRun available in every project; leave it out to limit it to the current one.
claude mcp add --transport http --scope user metarun https://metarun.dev/api/mcp02 · Sign in
In a Claude Code session, run /mcp, choose metarun and authenticate. MetaRun opens in your browser, where you pick read-only or read and change. From a plain shell, claude mcp login metarun does the same.
/mcp03 · Optional: add the skills too
The MetaRun plug-in bundles the same server with six mission skills (release handoff, worldwide pricing, localization, review inbox, ASO audit, store media).
claude plugin marketplace add metarun/metarun-skills
claude plugin install metarun-skills@metarunThen ask Claude Code
- Ask Claude Code: When build 312 finishes processing, give it to Internal and Beta Club, with What to Test written from the commits since build 309.
- Ask Claude Code: Pull this week's TestFlight crash feedback and match the stack traces to files in Sources/.
- Ask Claude Code: Expire every build older than 2.3.
claude -p runs one request with no interactive session. The browser sign-in can't complete inside -p, so sign in once interactively first, or configure the server with a personal access token in CI. Tools missing from --allowedTools are refused in -p mode.
Read-only check, safe to schedule
claude -p "List the latest five builds of com.example.app with processing state, expiry date and the tester groups each one is in. Read only." \
--allowedTools "mcp__metarun__apple_list_builds,mcp__metarun__apple_list_testflight_groups,mcp__metarun__apple_preview_assign_build_to_group,mcp__metarun__apple_preview_set_what_to_test,mcp__metarun__apple_preview_declare_build_encryption,mcp__metarun__apple_list_testflight_crash_feedback,mcp__metarun__apple_get_crash_log,mcp__metarun__apple_list_testflight_screenshot_feedback,mcp__metarun__apple_preview_expire_build"Only reads and previews are on that list, so nothing can reach App Store Connect unattended. Run applies in an interactive session where Claude Code can ask you.
Codex OpenAI
Run codex mcp add metarun --url https://metarun.dev/api/mcp; Codex detects MetaRun's sign-in and opens it in your browser.
01 · Add the server
Codex sees that MetaRun offers sign-in and starts it straight away, in your browser. Pick read-only or read and change.
codex mcp add metarun --url https://metarun.dev/api/mcp02 · Sign in again later
If the sign-in expires or you disconnected it in MetaRun's settings. --no-browser prints the link instead, for SSH sessions.
codex mcp login metarun03 · Or edit ~/.codex/config.toml
The Codex CLI, the IDE extension and Codex in the ChatGPT desktop app read the same file, so one entry covers all three.
[mcp_servers.metarun]
url = "https://metarun.dev/api/mcp"Then ask Codex
- Ask Codex: When build 312 finishes processing, give it to Internal and Beta Club, with What to Test written from the commits since build 309.
- Ask Codex: Pull this week's TestFlight crash feedback and match the stack traces to files in Sources/.
- Ask Codex: Expire every build older than 2.3.
codex exec runs one request without an interactive session and with its approval policy set to never. MetaRun's reads and previews still run, because they're marked read-only; anything that would ask is refused.
Read-only check, safe to schedule
codex exec "List the latest five builds of com.example.app with processing state, expiry date and the tester groups each one is in. Read only."Applies are refused in codex exec by design. Don't set MetaRun's approval mode to approve just to make them pass; keep App Store changes in an interactive session.
Cursor Anysphere
Add https://metarun.dev/api/mcp to ~/.cursor/mcp.json (or use the install link) and sign in to MetaRun when Cursor opens your browser.
01 · Add to ~/.cursor/mcp.json (or .cursor/mcp.json for one project)
{
"mcpServers": {
"metarun": {
"url": "https://metarun.dev/api/mcp"
}
}
}02 · Or use the install link
Opens Cursor with the server filled in.
https://cursor.com/link/mcp/install?name=metarun&config=eyJ1cmwiOiJodHRwczovL21ldGFydW4uZGV2L2FwaS9tY3AifQ%3D%3D03 · Sign in
When Cursor connects, MetaRun opens in your browser. Pick read-only or read and change, and you're back in the editor with the tools listed under MCP.
Then ask Cursor
- Ask Cursor: Write What to Test for build 312 from @CHANGELOG.md.
- Ask Cursor: Which tester groups have build 310?
- Ask Cursor: Show me the screenshot feedback testers sent today.
The Cursor CLI runs one request without the editor with agent -p. Allow only the read tools the request needs in ~/.cursor/cli-config.json (Mcp(metarun:tool_name) rules), and keep MetaRun's apply tools out of that list.
Read-only check, safe to schedule
agent -p "List the latest five builds of com.example.app with processing state, expiry date and the tester groups each one is in. Read only." --output-format jsonDon't run it with --force for MetaRun: that approves every tool, applies included.
Xcode Apple
In Xcode 27, add the plug-in from https://github.com/metarun/metarun-skills (Settings, Intelligence, Plug-ins, Add from URL) and click Sign in next to MetaRun.
01 · Add the MetaRun plug-in
In Xcode 27, open Settings, Intelligence, Plug-ins. Choose Add Plug-in, then Add from URL, and paste:
https://github.com/metarun/metarun-skills02 · Or with one click
Opens Xcode's plug-in sheet with the repository filled in.
xcode://agent-plugin-clone?repo=https%3A%2F%2Fgithub.com%2Fmetarun%2Fmetarun-skills03 · Sign in
Install MetaRun from the list, then click Sign in next to it. MetaRun opens in your browser; pick read-only or read and change.
04 · Ask the coding assistant
Claude Agent, Codex and Gemini in Xcode all get MetaRun's tools and its six workflow skills.
Attach build 312 to version 2.4 and tell me what blocks submission.Then ask Xcode
- Ask Xcode: I just uploaded build 312 from Organizer. Assign it to the internal group once it's processed.
- Ask Xcode: Get the crash log for the latest TestFlight crash report and find the line in this project.
- Ask Xcode: Our Info.plist doesn't declare encryption. Answer export compliance for build 312 as exempt.
Claude Anthropic
In Claude, open Customize, Connectors, Add custom connector, paste https://metarun.dev/api/mcp and click Connect to sign in to MetaRun.
01 · Add a custom connector
In Claude, open Customize, then Connectors, and choose Add custom connector. Name it MetaRun and paste the server URL:
https://metarun.dev/api/mcp02 · Connect
Click Connect. Claude opens MetaRun in your browser to sign in; pick read-only or read and change.
03 · Team and Enterprise
An Owner adds the connector once under Organization settings, Connectors. Each member then clicks Connect and signs in to their own MetaRun account.
Then ask Claude
- Ask Claude: Has my latest build finished processing?
- Ask Claude: Send build 312 to my beta testers.
- Ask Claude: What did testers report this week?
Frequently asked questions
What's the TestFlight external testers limit?
10,000 external testers per app, plus up to 100 internal testers who must be App Store Connect users. A public link can carry its own lower limit.
How long does TestFlight beta app review take?
Apple doesn't publish a figure for TestFlight App Review. The first build gets a full review and later builds of the same version might not need one. Leave a margin before any beta deadline.
What's the difference between TestFlight internal and external testers?
Internal testers are App Store Connect users on your team, up to 100, with no review. External testers can be anyone, up to 10,000, and need an approved build.
Why did my TestFlight build expire?
Every build expires 90 days after upload. Upload a new build to keep testing; testers move to it once it's in their group.
How does a TestFlight public link work?
You create it from an external group. Anyone who opens it on a device with TestFlight can join, up to your limit and within any device or OS criteria, and appears as Anonymous in App Store Connect.
What should I write in What to Test?
What changed in this build and where testers should look, in plain steps. It's shown to every group that has the build, so keep group-specific instructions out of it.
Can your agent upload a build to TestFlight?
Not through MetaRun: build upload belongs to Xcode, Xcode Cloud, fastlane or your CI. Everything after the upload (compliance, groups, notes, feedback) works through MetaRun.
Can it read crash reports from testers?
Yes. apple_list_testflight_crash_feedback returns the reports with tester comments and apple_get_crash_log returns the log, which your agent can match against your code.
Does it work with external tester groups?
Yes, internal and external groups both. The first build of a version to external testers still goes through Apple's Beta App Review.
What does export compliance mean here?
Apple's question about whether the build uses non-exempt encryption. The agent can answer it per build, or you can set ITSAppUsesNonExemptEncryption in Info.plist so Apple never asks.
Sources
- Apple: TestFlight overview
- Apple: Invite external testers
- Apple: Add internal testers
- Apple: App build statuses
- Apple: Provide export compliance information for beta builds
- Apple: Provide test information
- Apple: Add testers to builds
- Apple: View and manage tester information
- Apple: Stop testing a build
- Apple: Build upload statuses
- Apple: TestFlight
- Apple: Testing apps with TestFlight (for testers)
Related guides
Guide
The pre-submission checklist, every review status, export compliance, rejections and expedites.
Guide
The 7-day percentage schedule, the 30-day pause budget, and what to do when a bad build is rolling out.
Guide
What's New and promotional text: the limits, when each one locks, examples for every kind of update, and what App Review rejects.
Guide
Fill in App Privacy correctly: the 35 data types, tracking, SDKs, privacy manifests and required reason APIs.
All guides
Releases, TestFlight, pricing, subscriptions, localization, screenshots and more.
With MetaRun: App Store Connect MCP server
MetaRun
Do this from your AI agent or MetaRun's dashboard, with a preview before every change. 14-day free trial, no card.