The official CLI for TestApp.io app distribution

Upload your Android (APK) and iOS (IPA) apps directly from the command line.
Notify your team instantly. Get feedback faster.

🖥️
Try me 👇

Quick Install

curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash

Works on macOS (Intel & Apple Silicon) and Linux (x86_64, ARM). For Windows, see below.


How to update

Did you land here from a message that says "New version available"? Update like this.

1. Run the installer again

curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash

It replaces the old version with the latest one. Your settings (~/.ta-cli.json) are not touched.

On Windows, download the newest ta-cli-Windows-x86_64.exe from Releases and replace the old file (see Windows).

2. Check the version

ta-cli version

If you are up to date, it prints You are using the latest version. If not, it prints New version available and the number of the newest version.

What "update necessary due to breaking changes" means

Most updates are optional. The old version keeps working and only shows you the notice.

Sometimes we change something on our servers that an old ta-cli can no longer work with. Then ta-cli stops before uploading anything and prints:

⚠️ Update necessary due to breaking changes ⚠️
Error: update necessary due to breaking changes; install the latest ta-cli (https://help.testapp.io/ta-cli/) and run again

Nothing was uploaded. Run the installer above, then run your command again.

Updating if you use a plugin or CI

How you use ta-cli What happens What you do
Fastlane plugin The plugin checks ta-cli version before every upload. With self_update: true (the default) it installs a newer ta-cli by itself. With self_update: false it only warns about a normal update, and stops the lane when the update is required. Nothing, unless you set self_update: false. Then update by hand (step 1 above) or set it back to true. You can also set it with TESTAPPIO_SELF_UPDATE. The plugin itself is a separate update: bundle update fastlane-plugin-testappio.
GitHub Action Every run installs the latest ta-cli. Nothing, if your workflow uses testappio/github-action@v5. Older versions of the action (@v3, @v4) install a fixed old ta-cli. Change them to @v5.
Any other CI (GitLab, Jenkins, CircleCI, ...) Whatever your script does. If it runs the install line before ta-cli publish, it is already updating on every run. If you install ta-cli once on the build machine or in an image, run the installer again there.
Your own computer Nothing happens by itself. Step 1 above.

What is ta-cli?

ta-cli lets you upload app builds to TestApp.io without leaving your terminal. Perfect for:

  • Local development - Quick uploads while coding
  • CI/CD pipelines - Automated releases on every build
  • Team collaboration - Notify testers instantly with each release

Features:

  • Upload Android APK and iOS IPA files
  • Automatic app info extraction (version, bundle ID, etc.)
  • Git integration for release notes
  • Team notifications
  • Resumable uploads: if the connection drops, the upload carries on from where it stopped
  • Cross-platform support

Installation

macOS & Linux

curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash

This installs to /usr/local/bin/ta-cli. If that folder needs it, the installer asks for your password.

To install somewhere else, set INSTALL_DIR for the installer:

curl -Ls https://github.com/testappio/cli/releases/latest/download/install | INSTALL_DIR=$HOME/bin bash

Windows

Download from Releases:

File Architecture
ta-cli-Windows-x86_64.exe 64-bit (recommended)
ta-cli-Windows-i686.exe 32-bit

Rename it ta-cli.exe and add it to your PATH, or run it directly. To update, download the new file and replace the old one.

Verify Installation

ta-cli version

Quick Start

1. Get your credentials

Credential Where to find it
API Token portal.testapp.io/profile/tokens
App ID Open your app at portal.testapp.io/apps, then Integrations → Release → TestApp.io CLI → View Setup

2. Configure (interactive)

ta-cli config

Follow the prompts to enter your credentials.

3. Publish your app

ta-cli publish

That's it! Your app is uploaded, and your team is notified if you turned notifications on.


Commands

ta-cli publish

Upload your app to TestApp.io.

ta-cli publish [flags]
Flag Description Default
--api_token Your API token From config or environment
--app_id Your App ID From config or environment
--release android, ios, or both both
--apk Path to Android APK file From config or environment
--ipa Path to iOS IPA file From config or environment
--release_notes Custom release notes (up to 1,200 characters) None
--git_release_notes Use the latest git commit message as notes false
--git_commit_id Add the latest git commit ID to the notes false
--notify Notify team members false
--archive_latest_release Archive the previous latest release after a successful upload false
--upload_timeout The longest the upload may take in total, for example 45m or 3h. 0 turns the limit off. 2h
--config Custom config file path ~/.ta-cli.json

With --release both, ta-cli checks both files first and uploads only if both are fine.

ta-cli config

Interactive configuration wizard.

ta-cli config

ta-cli version

Show the version you have, and tell you if a newer one exists.

ta-cli version

ta-cli completion

Generate shell autocompletion scripts.

# Bash
ta-cli completion bash > /etc/bash_completion.d/ta-cli

# Zsh
ta-cli completion zsh > "${fpath[1]}/_ta-cli"

# Fish
ta-cli completion fish > ~/.config/fish/completions/ta-cli.fish

Upload time limit

An upload is allowed to take up to 2 hours in total. After that, ta-cli stops and tells you how much the server had received. Most builds finish in minutes, so you will rarely notice this. If you upload very large files over a slow connection, raise it. If you never want a limit, turn it off.

Value Meaning
45m, 90m, 3h Stop after this long
5400 A plain number is read as seconds (5400 seconds = 90 minutes)
0 No limit

Set it with the flag:

ta-cli publish --apk=./app-release.apk --release=android --upload_timeout=3h

or with the environment variable TESTAPPIO_UPLOAD_TIMEOUT (this is the easy way when you use Fastlane or the GitHub Action):

export TESTAPPIO_UPLOAD_TIMEOUT=3h

You can also put "upload_timeout": "3h" in your config file.

A wrong value (for example soon) or a negative one stops ta-cli before it uploads anything, with a message that says what is wrong.

Fastlane

Nothing to change in the plugin. The plugin starts ta-cli with the environment your lane already has, so set the variable where your lane runs:

export TESTAPPIO_UPLOAD_TIMEOUT=3h
fastlane ios beta

or in your Fastfile, before the upload step:

ENV["TESTAPPIO_UPLOAD_TIMEOUT"] = "3h"
upload_to_testappio(...)

GitHub Action

Nothing to change in the action. Add the variable to the step (or the job) in your workflow:

- name: Upload to TestApp.io
  uses: testappio/github-action@v5
  env:
    TESTAPPIO_UPLOAD_TIMEOUT: 3h
  with:
    api_token: ${{ secrets.TESTAPPIO_API_TOKEN }}
    app_id: ${{ secrets.TESTAPPIO_APP_ID }}
    file: ./app-release.apk

Configuration

Config File

Location: ~/.ta-cli.json

{
  "api_token": "your_api_token",
  "app_id": "your_app_id",
  "release": "both",
  "apk": "/path/to/app.apk",
  "ipa": "/path/to/app.ipa",
  "release_notes": "",
  "git_release_notes": true,
  "git_commit_id": false,
  "notify": true,
  "archive_latest_release": false,
  "upload_timeout": "2h"
}

ta-cli config writes the first nine settings. Add archive_latest_release and upload_timeout by hand if you want them. Note: running ta-cli config again rewrites the file and drops those two lines, so add them again afterwards.

Custom Config Path

ta-cli publish --config=/path/to/custom-config.json

Which setting wins

When the same setting is given in more than one place, the first one in this list wins:

  1. Command-line flags
  2. Environment variables
  3. The file given with --config
  4. .ta-cli.json in the current folder
  5. ~/.ta-cli.json

Environment Variables

Use environment variables instead of config files (ideal for CI/CD):

Variable Description
TESTAPPIO_API_TOKEN Your API token
TESTAPPIO_APP_ID Your App ID
TESTAPPIO_RELEASE Release type: android, ios, or both
TESTAPPIO_ANDROID_PATH Path to APK file
TESTAPPIO_IOS_PATH Path to IPA file
TESTAPPIO_NOTIFY Send notifications: true or false
TESTAPPIO_RELEASE_NOTES Custom release notes
TESTAPPIO_GIT_RELEASE_NOTES Use git commit as notes: true or false
TESTAPPIO_GIT_COMMIT_ID Include commit ID: true or false
TESTAPPIO_ARCHIVE_LATEST_RELEASE Archive the previous release: true or false
TESTAPPIO_UPLOAD_TIMEOUT Longest upload time, for example 3h. 0 = no limit. Default 2h.

Example:

export TESTAPPIO_API_TOKEN="your_token"
export TESTAPPIO_APP_ID="your_app_id"
ta-cli publish --apk=./app.apk --release=android

Older setups may use names without the TESTAPPIO_ start (for example API_TOKEN). They still work, but ta-cli prints a warning. Please rename them.


CI/CD Integrations

ta-cli works with any CI/CD platform that supports bash. Just install and run!

Quick Setup (Any CI/CD)

# 1. Install ta-cli
curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash

# 2. Upload your app
ta-cli publish \
  --api_token=$TESTAPPIO_API_TOKEN \
  --app_id=$TESTAPPIO_APP_ID \
  --apk=./app-release.apk \
  --release=android \
  --notify=true

Our GitHub Action and Fastlane plugin install ta-cli for you and keep it up to date (see How to update).

Integration Description Link
GitHub Action Native GitHub Actions integration testappio/github-action
Fastlane Plugin Native Fastlane plugin testappio/fastlane-plugin-testappio

Platform-Specific Guides

We have detailed guides for each CI/CD platform:

Platform Documentation
GitHub Actions View Guide
Fastlane View Guide
GitLab CI/CD View Guide
Jenkins View Guide
Bitrise View Guide
CircleCI View Guide
Travis CI View Guide
Azure Pipelines View Guide
Codemagic View Guide
Xcode Cloud View Guide

View All Integrations →


Examples

Android Only

ta-cli publish \
  --release=android \
  --apk=./app-release.apk \
  --notify=true

iOS Only

ta-cli publish \
  --release=ios \
  --ipa=./App.ipa \
  --notify=true

Both Platforms

ta-cli publish \
  --release=both \
  --apk=./app-release.apk \
  --ipa=./App.ipa \
  --release_notes="Bug fixes and improvements" \
  --notify=true

With Git Integration

ta-cli publish \
  --git_release_notes=true \
  --git_commit_id=true \
  --notify=true

Archive Previous Release

ta-cli publish \
  --apk=./app-release.apk \
  --archive_latest_release=true \
  --notify=true

Big file, slow connection

ta-cli publish \
  --apk=./app-release.apk \
  --upload_timeout=4h

Supported Platforms

Operating Systems

OS Architectures Binary
macOS Intel (x86_64), Apple Silicon (arm64), Universal ta-cli-Darwin-*
Linux x86_64, ARM64 (aarch64), ARMv7, i686 ta-cli-Linux-*
Windows x86_64 (64-bit), i686 (32-bit) ta-cli-Windows-*.exe

Supported File Types

Platform File Type Notes
Android .apk Debug or release signed APK
iOS .ipa Development, Ad-Hoc or Enterprise signed, with a profile that has not expired. Ad-Hoc builds need at least one device in the profile.

Files up to 4 GB are accepted by ta-cli. Your plan may set a lower limit.


Uninstalling

sudo rm /usr/local/bin/ta-cli
rm ~/.ta-cli.json  # Optional: remove config

Troubleshooting

"command not found: ta-cli"

The binary isn't in your PATH:

# Option 1: Restart your terminal
# Option 2: Add to PATH manually
export PATH=$PATH:/usr/local/bin
# Option 3: Use full path
/usr/local/bin/ta-cli version

The upload is slow, drops, or stops

You do not need to do anything for most of these. ta-cli handles them:

  • The connection drops. ta-cli asks the server how much it already has and carries on from there. You will see Upload interrupted (connection lost). Retrying in 5s (attempt 2 of 3).... Bytes the server already has are not sent again.
  • The connection goes quiet. If nothing is sent for 90 seconds, ta-cli treats the connection as stuck, stops it, and tries again the same way.
  • How many tries. ta-cli gives up after 3 tries in a row that make no progress. A try that moves the upload forward starts the count again, so a long upload on a bad connection can still finish.
  • The server lost the upload. ta-cli prints a warning and starts that upload again from the beginning, once.
  • The 2-hour limit. If the upload takes longer than --upload_timeout, ta-cli stops and says the upload did not finish within 2h0m0s, and how much the server had received. Raise the limit and run again.

If it still fails, the message ends with the name of the release that was created before the upload started. Running again creates a new release, so you may want to archive or delete the empty one in the Portal.

Other things to try: a different network, switching a VPN or proxy off, and making sure the file is not being written to while it uploads.

Errors that stop the upload straight away

Some problems cannot be fixed by trying again. ta-cli stops at once and prints one Error: line that says what is wrong. These are the common ones:

What the line says What it means What to do
unauthorized: not in a team or unauthorized: membership inactive The token's user is not an active member of a team. Ask a team owner to check your membership.
unauthorized on its own, or the upload server rejected the upload credentials (HTTP 401); check that your API token is valid Your API token is wrong, was deleted, or has expired. Make a new token at portal.testapp.io/profile/tokens and use it in --api_token or TESTAPPIO_API_TOKEN. In CI, update the secret.
plan limit reached, or your plan's limit was reached (HTTP 402); upgrade your plan or free up space in the Portal Your team has used up what its plan allows, such as storage. Archive or delete old releases in the Portal, or upgrade your plan.
file too large, or the file is larger than your plan's upload limit (HTTP 413) The file is bigger than your plan allows for one upload. Make the build smaller, or upgrade your plan.
... exceeds the 4294967296 byte limit The file is over 4 GB. This limit is in ta-cli itself. Make the build smaller.
APK file missing at ... / IPA path is empty The path is wrong or not set. Check --apk / --ipa (or TESTAPPIO_ANDROID_PATH / TESTAPPIO_IOS_PATH). With CI, the file must exist before the upload step runs.
--release_notes cannot exceed 1200 characters The release notes are too long. Shorten them.
update necessary due to breaking changes Your ta-cli is too old. See How to update.

Lines that start with [Android]: or [iOS]: tell you which build the error is about.

Invalid APK/IPA Error

  • APK: Ensure it's a valid Android package with AndroidManifest.xml, a package name, a version name and a version code.
  • IPA: Ensure it contains Info.plist and a valid provisioning profile. App Store builds are not accepted: use Development, Ad-Hoc or Enterprise. An expired profile, or an Ad-Hoc profile with no devices, is rejected before the upload starts.

Config Issues

Reset your configuration:

rm ~/.ta-cli.json
ta-cli config

Windows-Specific Issues

  • Run Command Prompt or PowerShell as Administrator if needed
  • Use forward slashes or escaped backslashes in paths: C:/path/to/app.apk

Support

Resource Link
Help Center help.testapp.io
CLI Documentation help.testapp.io/ta-cli
Email [email protected]
Issues GitHub Issues

Need help? Contact us. We're happy to assist!