Run an Appium Turbo test

This feature is currently in Beta and is limited to Private devices.

Learn how to run your Appium script with optimal execution speed and minimal latency using Appium Turbo Test Execution.

Why use Turbo Test Execution with Appium

Kobiton has analyzed thousands of Appium script executions from around the world and found that, on average, 28% of total execution time is spent on communication between the Appium client and the Appium server.

This overhead is influenced by factors such as:

  • Network speed and latency between the client and server

  • Geographical distance between where the test runs and where the Appium server is hosted

  • Payload type and frequency, including screenshots, logs, and element metadata exchanged during each command

Turbo Test Execution minimizes this communication overhead by streamlining the client–server interaction. As a result, your Appium scripts execute up to 28% faster on average without requiring any code changes.

When you use Xium, Kobiton’s optimized runtime, instead of Basic Appium 2:

  • Tests run 2.23× faster on iOS

  • Tests run 3.34× faster on Android

The combination of Turbo Test Execution and Xium delivers a significant reduction in test cycle time – especially valuable for large suites running across multiple devices or CI pipelines.

Prerequisites

  • A Kobiton account. Note down the below information:

  • Private devices available in the Kobiton account.

  • An Appium automation script that satisfies the below prerequisites.

    Turbo Test Execution for Appium supports XIUM and Basic Appium 2.

    Language

    Additional requirements

    Java

    Compatible with java-client 9.0.0 or newer.

    Contact Kobiton support if you want additional languages or frameworks supported.

Prepare the test project package

Expose environment variables

Alter your script to accept these environment variables. Do not hardcode the values of the required variables:

Environment variable Purpose Mapped Appium capability Required? Behaviour if omitted

KOBITON_URL

Appium server URL

The Appium server URL when you initialize the driver

Yes

Test run fails.

KOBITON_SESSION

Internal capability used by Kobiton to attach test report.

kobiton:session

Yes

Test report is not available.

KOBITON_UDID

UDID of the device under test

appium:udid

Yes

Test run fails.

KOBITON_USERNAME

Kobiton username

appium:username

Yes

Test run fails.

KOBITON_APIKEY

Kobiton API Key

appium:accessKey

Yes

Test run fails.

KOBITON_APP

App to test

appium:app

No

Manually set appium:app in your capabilities, or remove to test web apps.

KOBITON_RUNTIME

Determines whether to run a Basic Appium 2 or Xium script

kobiton:runtime

No

Manually set kobiton:runtime in your capabilities.

KOBITON_SESSION_NAME

Name of the test session

kobiton:sessionName

No

Manually set kobiton:sessionName in your capabilities.

KOBITON_SESSION_DESCRIPTION

Description for the test session

kobiton:sessionDescription

No

Manually set kobiton:sessionDescription in your capabilities.

Specify location for test artifacts

Configure your test script so that artifacts generated from the test run are placed in the output directory of the project’s root folder. This ensures that the artifacts can be downloaded from the test report after running.

A future update of Turbo Test will create this output directory automatically.
 // Create output directory
try {
    Files.createDirectories(Path.of("output"));
} catch (IOException ignored) {
}

// Write logs to a test_log.txt file under output
try (FileWriter log = new FileWriter("output/test_log.txt", true)) {
    log.write("=== TurboTest Run Started ===\n");
    log.write("Timestamp: " + LocalDateTime.now() + "\n");
} ...

Full example scripts

UIAutomator2 (Android)

public class SimpleTurboTest {
    public static void main(String[] args) {

        try {
            Files.createDirectories(Path.of("output"));
        } catch (IOException ignored) {
        }

        try (FileWriter log = new FileWriter("output/test_log.txt", true)) {
            log.write("=== TurboTest Run Started ===\n");
            log.write("Timestamp: " + LocalDateTime.now() + "\n");

            // Required environment variables
            String kobitonUrl  = System.getenv("KOBITON_URL");
            String udid = System.getenv("KOBITON_UDID");
            String kobitonSession = System.getenv("KOBITON_SESSION");
            String kobitonUsername = System.getenv("KOBITON_USERNAME");
            String kobitonApiKey = System.getenv("KOBITON_APIKEY");

            // Optional environment variables
            String app = System.getenv("KOBITON_APP");
            String sessionName = System.getenv("KOBITON_SESSION_NAME");
            String sessionDescription = System.getenv("KOBITON_SESSION_DESCRIPTION");
            String kobitonRuntime = System.getenv("KOBITON_RUNTIME");

            // Validate env vars
            if (kobitonUrl == null || kobitonSession == null || udid == null ||
                    kobitonUrl.isEmpty() || kobitonSession.isEmpty() || udid.isEmpty())  {
                System.err.println("Missing required env vars: KOBITON_UDID, KOBITON_URL, or KOBITON_SESSION");
                return;
            }

            // Provide default values for optional env vars if null or empty
            if (app == null || app.isEmpty()) {
                app = "https://example.com/downloads/sample.apk";
            }

            if (sessionName == null || sessionName.isEmpty()) {
                sessionName = "A Turbo Test session for Android";
            }

            if (sessionDescription == null || sessionDescription.isEmpty()) {
                sessionDescription = "A sample Turbo Test session for Android";
            }

            // Capabilities
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("kobiton:sessionName", sessionName);
            caps.setCapability("kobiton:sessionDescription", sessionDescription);
            caps.setCapability("appium:udid", udid);
            caps.setCapability("appium:app", app);
            caps.setCapability("appium:automationName", "UIAutomator2");
            caps.setCapability("kobiton:session", kobitonSession);
            caps.setCapability("appium:username", kobitonUsername);
            caps.setCapability("appium:accessKey", kobitonApiKey);
            caps.setCapability("kobiton:runtime", kobitonRuntime);

            // Initialize driver
            AndroidDriver driver = new AndroidDriver(new URI(kobitonUrl).toURL(), caps);

            // Save page source
            Files.writeString(Path.of("output/page_source.xml"), driver.getPageSource());

            // Screenshot
            File shot = driver.getScreenshotAs(OutputType.FILE);
            Files.copy(shot.toPath(), Path.of("output/screenshot.png"), StandardCopyOption.REPLACE_EXISTING);
            log.write("Screenshot saved\n");

            driver.quit();
            log.write("Completed successfully at " + LocalDateTime.now() + "\n");

        } catch (Exception e) {
            try (FileWriter err = new FileWriter("output/error.log", true)) {
                err.write("Exception: " + e.getMessage() + "\n");
                e.printStackTrace(new PrintWriter(err));
            } catch (IOException ignored) {}
            e.printStackTrace();
        }
    }
}

XCUITest (iOS)

public class SimpleTurboTest {
    public static void main(String[] args) {

        try {
            Files.createDirectories(Path.of("output"));
        } catch (IOException ignored) {
        }

        try (FileWriter log = new FileWriter("output/test_log.txt", true)) {
            log.write("=== TurboTest Run Started ===\n");
            log.write("Timestamp: " + LocalDateTime.now() + "\n");

            // Required environment variables
            String kobitonUrl  = System.getenv("KOBITON_URL");
            String udid = System.getenv("KOBITON_UDID");
            String kobitonSession = System.getenv("KOBITON_SESSION");
            String kobitonUsername = System.getenv("KOBITON_USERNAME");
            String kobitonApiKey = System.getenv("KOBITON_APIKEY");

            // Optional environment variables
            String app = System.getenv("KOBITON_APP");
            String sessionName = System.getenv("KOBITON_SESSION_NAME");
            String sessionDescription = System.getenv("KOBITON_SESSION_DESCRIPTION");
            String kobitonRuntime = System.getenv("KOBITON_RUNTIME");

            // Validate env vars
            if (kobitonUrl == null || kobitonSession == null || udid == null ||
                    kobitonUrl.isEmpty() || kobitonSession.isEmpty() || udid.isEmpty())  {
                System.err.println("Missing required env vars: KOBITON_UDID, KOBITON_URL, or KOBITON_SESSION");
                return;
            }

            // Provide default values for optional env vars if null or empty
            if (app == null || app.isEmpty()) {
                app = "https://example.com/downloads/sample.ipa";
            }

            if (sessionName == null || sessionName.isEmpty()) {
                sessionName = "A Turbo Test session for iOS";
            }

            if (sessionDescription == null || sessionDescription.isEmpty()) {
                sessionDescription = "A sample Turbo Test session for iOS";
            }

            // Capabilities
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("kobiton:sessionName", sessionName);
            caps.setCapability("kobiton:sessionDescription", sessionDescription);
            caps.setCapability("appium:udid", udid);
            caps.setCapability("appium:app", app);
            caps.setCapability("appium:automationName", "XCUITest");
            caps.setCapability("kobiton:session", kobitonSession);
            caps.setCapability("appium:username", kobitonUsername);
            caps.setCapability("appium:accessKey", kobitonApiKey);
            caps.setCapability("kobiton:runtime", kobitonRuntime);

            // Initialize driver
            IOSDriver driver = new IOSDriver(new URI(kobitonUrl).toURL(), caps);

            // Save page source
            Files.writeString(Path.of("output/page_source.xml"), driver.getPageSource());

            // Screenshot
            File shot = driver.getScreenshotAs(OutputType.FILE);
            Files.copy(shot.toPath(), Path.of("output/screenshot.png"), StandardCopyOption.REPLACE_EXISTING);
            log.write("Screenshot saved\n");

            driver.quit();
            log.write("Completed successfully at " + LocalDateTime.now() + "\n");

        } catch (Exception e) {
            try (FileWriter err = new FileWriter("output/error.log", true)) {
                err.write("Exception: " + e.getMessage() + "\n");
                e.printStackTrace(new PrintWriter(err));
            } catch (IOException ignored) {}
            e.printStackTrace();
        }
    }
}

Package the test project

Run your tests locally to verify they work.

Package the project into a .zip that contains the compiled .jar and all runtime dependencies.

Name the archive, e.g., test_runner.zip.

Upload test runner

Method 1: Using Kobiton Portal

Log in to the Kobiton Portal using your Kobiton username/email and password.

Navigate to the Device list by selecting Devices on the navigation pane.

Select the 3-dot icon on the Android device you plan to use for testing.

Navigate to Devices and select the 3-dot icon on an Android device

Select Automation Settings.

Note down the device UDID, then select Automation Settings

In the Framework dropdown, select UIAutomator/ Espresso or XCUITest.

Select UIAutomator or Espresso

Scroll down until you find the Test Runner section, then select Upload Test Runner.

Select Upload Test Runner under the Test Runner section

Choose the test_runner.zip file and select Open.

When the file finishes uploading, note down the value of Test Runner Url. This is the <test_runner> to be used later.

Note down the value of Test Runner URL

The Test Runner URL expires after about 12 hours.

Method 2: Using Kobiton API

Run the following API endpoints, in order, to upload the test runner to Kobiton:

Note down the value of url and test_runner_id from the response of the Get test runner download URL endpoint. Either of these values can be the <test_runner> to be used later.

The url (test runner download URL) expires after about 12 hours. It is recommended to use the test_runner_id (test runner ID) as it does not expire.

Run the automation test

Open a terminal and run the following command. Replace placeholder values with your own.

curl --location '<api_base_url>/v2/sessions/native' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <credentials>' \
--data '{
  "test_framework": "<kobiton_runtime>",
  "test_runner": "<test_runner>",
  "session_name": "<kobiton_session_name>",
  "session_description": "<kobiton_session_description>",
  "app": "<kobiton_app>",
  "udid": "<udid>",
  "device_name": "<device_name>",
  "device_tags": [<array_of_device_tags>],
  "platform_version": "<device_os_version>",
  "env": {<environment_variables>},
  "args": [<array_of_arguments>],
  "run_command": "<run_command>",
  "execution_mode": "<execution_mode>",
  "device_wait_timeout": <device_wait_timeout>,
}'

The system finds the first Private device that matches <udid>, then <device_name>, and then <array_of_device_tags>. It then runs the test script on the device.

Appium Turbo Test execution is not available for Public devices.

If the request is successful, the response is similar to the below:

  • If execution_mode is IMMEDIATE:

{
  "session_id": <session_id>,
  "device_udid": "<device_udid>",
  "device_id": <device_id>,
  "request_id": "<appium_request_id>",
  "test_report_download_url": "<test_report_url>"
}
  • If execution_mode is QUEUED:

{
  "queue_id": "<queue_id>",
  "requested_at": "<requested_at>",
  "query_params": {
    "query_param_1": "value"
  }
}

See the next sections for request and response parameter reference.

API authentication reference

  • <api_base_url>

    • Type: string

    • Required: Yes

    • Example: https://api.kobiton.com

    • Description: The API base URL.

  • <credentials>

    • Type: string

    • Required: Yes

    • Example: a29iaXRvbmFkbWluOjI4Nzk4MTI0LTItZGEtd2Rhdy0tNDMtMjQzMjQ=

    • Description: Base64-encoded username_or_email:api_key.

Request parameter reference

  • test_framework

    • Type: enum

    • Required: Yes

    • Example: APPIUM, XIUM

    • Description: Use APPIUM to run Basic Appium 2 script or use XIUM to run XIUM script

    • Note: requires KOBITON_RUNTIME environment variable

  • test_runner

    • Type: string

    • Required: Yes

    • Example: either of the below:

      • https://kobiton-*.s3.amazonaws.com/test-runner/users/17/test_runner-xyz.zip

      • f8b6967d-1975-4c08-92b7-037512416127

    • Description: Can be either of the below:

      • Download URL of the test runner

      • The unique ID of the test runner

  • session_name

    • Type: string

    • Required: No

    • Example: A Turbo Test session

    • Description: The display name of the session

    • Note: requires KOBITON_SESSION_NAME environment variable.

  • session_description

    • Type: string

    • Required: No

    • Example: A Turbo Test session on Android

    • Description: The description of the session

    • Note: requires KOBITON_SESSION_DESCRIPTION environment variable.

  • app

    • Type: string

    • Required: No

    • Example: kobiton-store:v34321, https://example.com/downloads/sample.ipa

    • Description: The app to test.

    • Note: requires KOBITON_APP environment variable.

  • udid

    • Type: string

    • Required: Yes if device_tags and device_name is not provided

    • Example: 8bf2c82a

    • Description: UDID of the Kobiton Private device

  • device_name

    • Type: string

    • Required: Yes if device_tags and udid is not provided

    • Example: Pixel 8, iPad ,

    • Description: Name of the Kobiton Private device. Wildcard (*) is supported.

  • platform_version

    • Type: string

    • Required: No

    • Example: 12

    • Description: OS version of the device

  • device_tags

    • Type: array of strings

    • Required: Yes if udid and device_name is not provided

    • Example: [[ "healthy" ], [ "project", "dev" ]]

    • Description: Tags to filter Private devices. Follow the below formats:

      • Single group with a single tag: [[ "healthy" ]] (Only select devices with healthy tag)

      • Single group with multiple tags (OR within group): [[ "project", "dev" ]] (Select devices with either project or dev tag)

      • Multiple groups (AND across groups): [[ "healthy" ], [ "project", "dev" ]] (Select devices with healthy and either project or dev tag)

  • device_tag_type

    • Type: enum

    • Required: No

    • Values: private or public

    • Description:

      • Only applies when device_tags is provided.

      • When specified, filters by public or private device tags only. Otherwise, both private and public device tags are used.

  • env

    • Type: object (string keys and values)

    • Required: No

    • Example: { "VARIABLE_1": "value1", "VARIABLE_2": "value2" }

    • Description: Additional environment variables to export

  • args

    • Type: array of strings

    • Required: No

    • Example: [ "--arg value", "--another-arg value2" ]

    • Description: Additional command-line arguments for your test

  • run_command

    • Type: string

    • Required: Yes

    • Example: java -jar SimpleTurboTest.jar

    • Description: Command that runs the compiled .jar file of your script. Includes all command arguments here.

  • execution_mode

    • Type: enum

    • Required: No

    • Values: IMMEDIATE (default) or QUEUED

    • Description: Specify whether the test should be executed immediately or in a queue.

      • IMMEDIATE: test executes immediately if the device is available. If there is no device available, the test terminates.

      • QUEUED: test is put in a queue waiting for execution. If system cannot find an available device after the timeout period, the test terminates.

  • device_wait_timeout

    • Type: integer (in seconds)

    • Condition: only applies when execution_mode is QUEUED

    • Required: No

    • Default value: 900Minimum: 1Maximum: 86400

    • Example: 20

    • Description: The timeout period for queued execution mode. If system cannot find an available device after the timeout period, the test terminates.

Response parameter reference

Immediate execution mode

  • session_id

    • Type: integer

    • Example: 1135

    • Description: ID of the session where the test executed. Use this ID to query the session details.

  • device_udid

    • Type: string

    • Example: 5***1FDCH730X1

    • Description: UDID of the device under test. Use this to find the session.

  • device_id

    • Type: integer

    • Example: 31234

    • Description: ID of the device under test. Use this ID to query the device details.

  • request_id

    • Type: string

    • Example: d8c22b16-e863-47ed-b2b5-c1103c4a91a0

    • Description: Appium request ID of the test run. Note: this is not Kobiton session ID.

  • test_report_download_url

    • Type: string

    • Example: https://kobiton-acme.s3.amazonaws.com/organizations/6/sessions/d8c22b16-e863-47ed-b2b5-c1103c4a91a0/test-report.zip

    • Description: URL to download the test report. Only downloadable after the test has finished.

Queued execution mode

  • queue_id

    • Type: string

    • Example: 5a035e50-7032-4396-89ee-78428e8e3a9e

    • Description: ID of the queue. Use this value to query the status of the test execution in the queue.

  • requested_at

    • Type: datetime (UTC)

    • Example: 2025-11-05T04:52:32.871Z

    • Description: UTC date and time when the request is made.

  • query_params

    • Type: object

    • Description: The body of the request for reference.

Check status for queued execution mode

For requests made with queued execution mode, run the following command in a terminal to check the status. Replace placeholder values with your own.

curl --location '<api_base_url>/v2/sessions/queue/<queue_id>' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <credentials>'
  • <queue_id> is obtained from the response of the request.

The response is similar to that of the test run request, with 2 additional parameters:

  • status

    • Type: enum

    • Values:

      • QUEUED: the test is still waiting to be executed

      • TIMED_OUT: the test timed out before an available device can be found

      • INITIATED: the test is executed

    • Description: Status of the execution.

  • session_id

    • Type: integer

    • Condition: this value is only returned when status is INITIATED

    • Example: 1135

    • Description: ID of the session where the test executed. Use this ID to query the session details.

Download test report

Method 1: Using Kobiton Portal

Log in to the Kobiton Portal using your Kobiton username/email and password.

Navigate to Sessions, then find a session associated with the target device of the test. You can enter <session_id> in the session search box to quickly filter sessions.

Select the session in the search results to navigate to Session Overview.

Under Test Report, select Download to save the test report to your computer. Note: The test report can only be downloaded for sessions with the status: Complete.

Method 2: Using Kobiton API

For immediate execution mode, the report download URL is available in the response of the automation test run request.

Note: the test report download URL expires after about 12 hours. To obtain a new test report download URL, follow the same steps for queued execution mode below.

For queued execution mode, run the below command in the terminal to retrieve the test report download URL. Replace placeholder values with your own.

curl --location '<api_base_url>/v2/sessions/<session_id>' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <credentials>'

The test report download URL is the value of test_report_url in the response. Note: if the test_report_url is not available, wait until the test has finished executing before trying again.

Sample demo script

Download and extract the sample demo script.

The sample includes three main folders:

  • TurboTestAndroid – Contains scripts for Android devices.

  • TurboTestiOS – Contains scripts for iOS devices.

  • artifacts – Contains the precompiled .jar and .zip files for both Android and iOS.

Use the precompiled test runners

You can use the provided test runners to run a Turbo Test Session.

  • Locate the test runners at artifacts/test_runners.zip. This file includes .jar files for both Android and iOS tests.

  • Upload the test runners to Kobiton and obtain the test runner download URL or test runner ID.

  • Find a device in Kobiton and note down its UDID.

  • Find an app to test and note down its Kobiton store ID or download URL.

  • Make the following API requests in your terminal after updating the placeholders with your values. You can change execution_mode to QUEUED to queue multiple tests.

Android:

curl --location '<api_base_url>/v2/sessions/native' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <credentials>' \
--data '{
  "test_framework": "XIUM",
  "test_runner": "<test_runner_url_or_id>",
  "session_name": "A Turbo Test session on Android",
  "session_description": "A session to demo the features of Turbo Test on Android",
  "app": <app>,
  "udid": "<udid>",
  "run_command": "java -jar TurboTestAndroid.jar",
  "execution_mode": "IMMEDIATE"
}'

iOS:

curl --location '<api_base_url>/v2/sessions/native' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <credentials>' \
--data '{
  "test_framework": "APPIUM",
  "test_runner": "<test_runner_url_or_id>",
  "session_name": "A Turbo Test session on iOS",
  "session_description": "A session to demo the features of Turbo Test on iOS",
  "app": <app>,
  "udid": "<udid>",
  "run_command": "java -jar TurboTestiOS.jar",
  "execution_mode": "IMMEDIATE"
}'
  • Download the test report from the URL in the response.

    • If execution_mode is QUEUED, follow the instructions from the Download test report section to obtain the test report.

  • The test report contains:

    • A stdout.log file that captures the output of the run command.

    • A stderr.log file that captures the error(s) when executing the run command, if any.

    • An output folder that contains the test log, XML page source, and screenshot of the app under test.

Modify and recompile scripts

You can modify the test scripts to fit your testing needs. After making changes:

  • Recompile the .jar files.

  • Package them as .zip test runners.

  • Upload the updated test runners to Kobiton.

Limitation

  • Mixed sessions are not supported for Appium Turbo Test.