Store Submission
Getting a build into TestFlight usually means a Mac at the end of the pipeline, running Xcode’s Organizer or the Transporter app, and then a trip to App Store Connect to add the build to your tester groups. VibeView removes that last Mac and the trip.
This guide covers the upload and getting the build to your testers. For store screenshots, see Make App Store screenshots without a Mac. The same commands also send tvOS builds to TestFlight; Build an Apple TV app without a Mac covers that side.
A few TestFlight terms come up throughout. An internal group is people on your App Store Connect team. An external group is anyone you invite by email. What to Test is the note testers see with a build. Beta App Review is Apple’s check of a build before external testers can install it; internal groups don’t need it.
What you need
- An Apple Developer Program membership. Apple requires it to sign and publish an app, with or without a Mac.
- A VibeView account with the CLI installed. Run
npm install -g vibeview, thenvibeview login. - An App Store Connect API key, stored once in VibeView (next section). To send builds to TestFlight groups, it needs the App Manager or Admin role.
- Signing credentials for the app, generated with that key or uploaded (see Signing without a Mac).
- The app record in App Store Connect, created once per app. Apple only accepts uploads for apps that already exist there. Step 2 below creates it.
Create the App Store Connect API key
With the key, VibeView can create certificates and upload builds for your Apple team. You never share your Apple ID password or answer a two-factor prompt. You create the key in a browser, on any OS:
-
Sign in to App Store Connect as the Account Holder or an Admin. Apple lets only those roles create team keys. If your team has never used the API, the Account Holder must first request access on the same page, and Apple approves it.
-
Go to Users and Access → Integrations → App Store Connect API → Team Keys and generate a key with the App Manager or Admin role. Write down the Key ID and the Issuer ID shown on that page.
-
Download the
.p8file and keep it safe. You can download it only once. -
Store it in VibeView. You need to be an Admin in your VibeView organization (a separate role from Apple’s Admin):
vibeview credentials asc-key add --name team --key-id <KEY_ID> --issuer-id <ISSUER_ID> --file AuthKey_<KEY_ID>.p8
You can also add it in the dashboard under Builds → Stores. Once stored, the key can’t be viewed or downloaded again. vibeview credentials asc-key list shows its name (team here), key ID and issuer ID. To rotate it, add a new key with the same name. To stop using it, run vibeview credentials asc-key rm team.
Signing without a Mac
The usual way to get an iOS distribution certificate starts with Keychain Access on a Mac. With the API key stored, you skip that: the credentials generate command in step 1 below does it for you.
VibeView creates an Apple Distribution certificate for your team, or reuses the one it made before. It registers the bundle identifier with Apple if needed and creates an App Store provisioning profile. Production builds use the result right away.
Already have a .p12 and a .mobileprovision? Upload them instead with vibeview credentials add --platform ios --file cert.p12 --profile app.mobileprovision. App Signing covers both routes, expiry, and how a build picks its credential.
From source to your testers, step by step
-
Create signing credentials (once).
vibeview credentials generate --platform ios --name release --app <app-id><app-id>is the app’s VibeView id, not anything from Apple. It is theappIdin yourvibeview.json, andvibeview list-appslists them. If the app isn’t in VibeView yet, pass--bundle-id com.example.appinstead of--app. -
Create the app record (once). In App Store Connect, open Apps → + → New App, choose the platform, and pick your bundle identifier. Step 1 registered it with Apple, so it is in the list now. No upload is needed; the record alone is enough.
-
Check that Apple can accept the upload. This needs no build:
vibeview submit --check --platform ios --bundle-id com.example.app --group "QA team"readymeans App Store Connect knows the app and your stored key works. Otherwise it names the problem (no app record, no stored key, or a refused key) and how to fix it. From CLI 0.56.0, the check also lists the app’s TestFlight groups and the latest TestFlight build number. It also says what external testers would be waiting on, such as Beta App Review. With--group, it fails on a group name the app doesn’t have. -
Build a signed release.
vibeview build --cloud --production --platform iosThe first time, the CLI asks for the command that builds your signed release and where the
.ipalands, then saves both as theproductionprofile invibeview.json. In CI or with--jsonit can’t ask, so commit that profile first. The build runs on VibeView’s cloud Macs and is signed with your credential. The signed.ipalands on your Builds page. To keep Apple from refusing a reused build number, see Build numbers, handled. -
Submit it and send it to testers.
vibeview submit --platform ios --latest --group "QA team" \ --what-to-test "Try the new checkout" --no-uses-encryption --wait-distributionThe TestFlight flags need CLI 0.55.0 or later:
--latestpicks your newest successful production build;--build <id>submits a specific one.--groupnames a TestFlight group as it is called in App Store Connect. Repeat it for several.--what-to-testis the note testers see, up to 4,000 characters (or--what-to-test-file). It is required when a group is external.--no-uses-encryptionanswers Apple’s export compliance question for the app. Use--uses-encryptionif the app uses encryption beyond the exempt cases; see Export compliance.--wait-distributionkeeps the command running until the build reaches your testers (next step).
Without
--group(orgroupsinvibeview.json), the build goes to TestFlight with no groups added, and you add testers in App Store Connect. -
Let it reach your testers. With
--wait-distribution, the command keeps following the build after the upload, prints each step as it changes, and exits with a code your pipeline can read (below). Without it, the command exits when the upload ends and VibeView keeps following the build on its own; the build’s Store submissions card on its page in the dashboard shows where it is.
What happens after the upload
The upload succeeds once Apple accepts the binary. VibeView then follows the build in App Store Connect until it reaches your testers. The build’s Store submissions card shows each step:
- Processing by Apple. Apple processes the build. VibeView checks on its own.
- Export compliance. VibeView answers Apple’s encryption question from your Info.plist or your saved answer (see Export compliance).
- What to Test. Your notes are added to the build.
- Internal groups. The build is added to the internal groups you chose.
- Beta App Review. For external groups, the build is sent to Apple’s review.
- External groups. The build is added to the external groups you chose.
A step you didn’t ask for shows as Skipped. A problem in these steps never undoes the upload. It shows as Needs your action or Distribution failed instead.
The submission’s state shows on the build’s Store submissions card, in the Store column on the Builds page and on the Submissions tab:
| State | What it means |
|---|---|
| TestFlight · Processing | Apple is processing the build |
| Sending to testers | VibeView is answering export compliance, adding the notes, adding the build to your groups or sending it to Beta App Review |
| In Beta App Review | Sent to Beta App Review and added to your external groups. Apple releases it to external testers once it approves the build; internal groups already have it |
| Waiting on Apple | No Beta App Review verdict after 7 days. VibeView keeps checking every 6 hours |
| Available to testers | Done: the build is in TestFlight with the groups you chose |
| In TestFlight | Done, with no groups added |
| Needs your action | Something only you can fix; the build’s Store submissions card says what and where |
| Distribution failed | Apple marked the build invalid, it expired, or the app or build no longer exists in App Store Connect |
When the build needs your action, its Store submissions card names the fix and where to make it. Once you’ve made it, choose Check again. For things like missing beta test information or an open export compliance question, VibeView also looks again on its own every 30 minutes. When it needs your action lists every case.
Internal and external groups
- Internal groups are people on your App Store Connect team, up to 100. They get the build as soon as Apple has processed it and export compliance is answered.
- External groups can hold up to 10,000 people per app, across all its external groups. They need Apple’s Beta App Review first. Apple also needs What to Test notes, beta test information (a beta app description and a feedback email) and Beta App Review contact details. VibeView sends the build for review and adds it to your external groups. Apple releases it to them after it approves the build.
Each build stays testable for 90 days after upload.
The internal limit and the 90 days come from Apple’s TestFlight overview, and the external limit from Apple’s invite external testers page (both checked 25 October 2026). VibeView doesn’t change them.
Before you send to an external group for the first time, go through the TestFlight external testing checklist.
Export compliance
For each build, Apple asks whether the app uses encryption beyond the exempt cases, such as HTTPS and the system’s standard crypto. Testers can’t install the build until it’s answered. VibeView answers from the first of these that has an answer:
- Your Info.plist. When the app sets
ITSAppUsesNonExemptEncryption, Apple reads it from there. Set it toNOonly if the app uses no encryption beyond the exempt cases. - The answer saved for the app.
--uses-encryptionor--no-uses-encryptiononvibeview submit, or the question in the dashboard’s Submit dialog, saves your answer for every later build of the app.
With no answer anywhere, distribution stops at Export compliance, and the build’s Store submissions card asks the question. If the app does use non-exempt encryption, Apple needs your export compliance documents. You upload them in App Store Connect, and VibeView continues once Apple has them. See Apple’s export compliance overview.
Seeing Missing Compliance on a build in App Store Connect? TestFlight “Missing Compliance”: fix it once covers the Info.plist key, the Expo setting and how to decide your answer.
From the dashboard
Finished production builds on the Builds page have a Submit to store action (on the build’s own page, Submit to TestFlight). Once App Store Connect answers, the dialog shows:
- Testers: the app’s TestFlight groups, each marked Internal or External. A group marked Gets every build (an App Store Connect setting) already receives every build, so it is shown checked. With no groups yet, Create a group makes one without leaving VibeView.
- What to Test: required while an external group is chosen. Reuse last notes copies in the notes you sent last time, and What to Test, by language adds notes in other languages.
- Apple’s export compliance question, the first time for an app.
- Ready to send: whether the build number is newer than the latest TestFlight build, whether the app has groups and, for an external group, whether the beta test information and the Beta App Review contact details are filled in. Add it here opens the part that is missing.
The button reads Upload and send to testers when you chose a group. Use these settings next time keeps the key and the groups for the app’s next build.
TestFlight details (from the dialog, or Builds → Stores → your app) sets what Apple needs before external testing, without opening App Store Connect: the test information in each language, the Beta App Review contact and sign-in account, new groups, and external testers added by email.
From the command line, vibeview testflight info, set-info, set-review-contact, groups, create-group and add-testers do the same. They need CLI 0.57.0 or later.
To invite a list of external testers from a file, see Add TestFlight testers from the command line. For notes in other languages from a folder in your repository, see Release notes and What to Test in many languages.
Exit codes for CI
With --wait-distribution, the command checks every 15 seconds and exits:
| Exit | When |
|---|---|
0 (settled) | The build is in TestFlight with your groups, is in Beta App Review (Apple releases it to external testers after approval), or is still waiting for Apple’s verdict after 7 days |
0 (time limit) | Distribution hasn’t settled 2 hours 15 minutes after the wait began. The command prints the build page, where VibeView keeps following it |
1 | Distribution needs your action (the message says what to do), failed or was stopped, or the upload itself failed |
2 | Your API token stopped working during the wait. VibeView keeps following the build |
To pick a submission up later, for example after vibeview submit --no-wait, run vibeview submissions status <id> --wait-distribution (CLI 0.56.0 or later). The CLI reference has every exit code and the --json events.
For a complete workflow that sends every version tag to TestFlight, see GitHub Actions to TestFlight, no Mac runner.
What stays in App Store Connect
VibeView uploads the build and gets it to your TestFlight groups. These stay in App Store Connect:
- Submitting a version for App Store review, and phased release.
- The App Store listing, screenshots, pricing and privacy labels.
- Removing testers, renaming or deleting a group, adding internal testers and creating a public link.
- Tester counts and who installed a build.
To ship a build that testers have to the App Store, add it to a version in App Store Connect and submit that version for review there. Done in the store’s console lists where each task lives.
Build numbers, handled
Apple refuses an upload whose build number (CFBundleVersion) it has seen before. Set "autoIncrement": true on the production profile in vibeview.json. Every production build then gets the next number from a counter VibeView keeps per app and platform. The number reaches your build as the VIBEVIEW_BUILD_NUMBER environment variable; wire it in once, as Automatic build numbers shows.
For an app already in TestFlight, VibeView checks your recent uploads in App Store Connect before handing out the first number, and starts above the highest. You can also seed the counter yourself with vibeview versions set.
Common errors and fixes
A refused submission says why in its log. Fix the cause and submit again.
| Symptom or message | What it means | Fix |
|---|---|---|
| Apple doesn’t know this app yet | No app record, or its bundle identifier doesn’t match the build’s | Create the record in Apps → + → New App with the build’s bundle identifier |
| Apple already has build N for this version | The build number was used before | Raise the build number and rebuild. With automatic build numbers on, set the counter to N before rebuilding (vibeview versions set N --app <app-id> --platform ios; the next build gets N + 1). Without them, raise CFBundleVersion in your project |
| No App Store Connect key is stored for this organization | No API key yet | vibeview credentials asc-key add, or Builds → Stores |
| This organization has several App Store Connect keys | VibeView needs to know which key to use | Pass --asc-key <name>, or choose one in the dashboard |
| The New App form doesn’t list your bundle identifier | The identifier isn’t registered with Apple yet | Generate credentials first (it registers the identifier), or register the bundle identifier as an App ID under Certificates, Identifiers & Profiles at developer.apple.com |
| Generating credentials stops at the certificate limit | Apple caps each team at a small number of distribution certificates | Revoke an unused certificate at developer.apple.com, or upload your own .p12. VibeView never revokes one for you |
| A production build is refused for an expired credential | Every credential that applies to the app has expired | Generate or upload a replacement; profiles usually expire before certificates |
A --group name is refused | The app has no TestFlight group with that name | The message lists the app’s groups. Names match in any case |
| The key can’t manage TestFlight testers | The App Store Connect key lacks the App Manager or Admin role | Create a key with one of those roles, delete the old key in Builds → Stores and add the new one under the same name |
| Add beta test information or Add Beta App Review contact details | Apple needs these before external testing | Choose Add it here on the build’s card, or set them in TestFlight details |
| Another build is in Beta App Review | Apple reviews one build of a version at a time | Wait for that build’s verdict, or remove it from review in App Store Connect. VibeView never removes it for you |
| Apple rejected this build in Beta App Review | Apple’s reviewers turned the build down; their message is in App Store Connect (TestFlight → App Review) | Fix the issue and send a new build with a higher build number |
The check in step 3 catches a missing app record, a missing key or a wrong group name before you build. The full lists are in Common refusals and When it needs your action.
Other ways to upload to TestFlight
VibeView isn’t the only route. Here is what each tool’s own docs say (checked 23 October 2026).
On a Mac, Apple’s own tools do it: Xcode’s Organizer, altool (through xcrun) and the Transporter app, per Apple’s upload builds page. Without a Mac:
- Transporter from the command line. Apple’s Transporter user guide lists Windows 11 and a Red Hat Linux distribution among the systems the command-line tool supports. It uploads a signed
.ipa; you still need a way to build and sign one. - EAS Submit. Expo’s iOS submit docs say it works on macOS, Linux and Windows. It submits a production
.ipa, which Expo recommends building with EAS Build in Expo’s cloud. Our EAS Build comparison covers the differences. - fastlane.
upload_to_testflightaccepts an App Store Connect API key and uploads through Apple’s Transporter. Its docs describe a Linux setup. Building the.ipastill needs Xcode somewhere, usually a hosted Mac CI runner.
VibeView keeps the build, the signing credentials, the upload and the path to your testers in one place.
Android and Fire TV use the same command
For Android and Android TV, vibeview submit --platform android --latest --track internal sends the build to Google Play, using a Google Play service-account key. Use --platform androidtv for an Android TV app. A track is the Google Play release channel the build goes to: internal, alpha, beta or production.
--release-notes adds release notes in your Google Play listing’s default language. --notes-dir adds other languages, one <code>.txt file per language, and needs CLI 0.58.0 or later. The same flag sends What to Test notes in other languages on TestFlight.
--release-status inProgress --rollout 0.1 starts a staged rollout, which you raise later in Play Console. In the dashboard, the Submit dialog offers Staged rollout with a percentage. It also offers Don’t send for review, for when Google asks you to send changes for review from Play Console yourself.
For Fire TV and Fire tablets, --store amazon sends an Android or Android TV .apk to Amazon Appstore review. The Store Submission docs cover the one-time setup for each store.
Submit a Fire TV app to the Amazon Appstore walks through the Amazon side step by step.
When you’d use this
The obvious case is a Windows or Linux team shipping a React Native app with no Mac at all. It also suits teams with Macs who would rather not keep a CI runner on the right Xcode or spread signing certificates across laptops.
Frequently asked questions
Can I upload an .ipa to TestFlight from Windows?
Yes. Build the .ipa as a VibeView production build, then run vibeview submit from Windows; the
upload itself happens on VibeView’s side.
Why can't I see my build in TestFlight?
It is usually still processing. The build’s Store submissions card on its page, and the Store column on the Builds page, show TestFlight · Processing until Apple finishes. If Apple marks the binary invalid, the state turns to Distribution failed, and Apple emails the reason to your team’s Account Holder.
Can I send a build to external testers from the command line?
Yes. Pass an external group with --group and a note with --what-to-test. VibeView sends the
build to Beta App Review and adds it to the group, and Apple releases it to those testers once it
approves the build. --wait-distribution exits 0 while the build is in review.
Does VibeView submit my app for App Store review?
No. VibeView gets the build to your TestFlight testers. Adding it to an App Store version and submitting that version for review stay in App Store Connect.
Can I test the app before uploading it?
Yes, but not the signed .ipa: it is a device build, and simulators can’t install it. Run a
simulator build of the same code on a cloud iPhone first, as in Build a React Native app without
a Mac.
Try it yourself
Open a live iOS simulator, Android emulator, Apple TV, Android TV or Roku in your browser.
Start free