BitBar: Mobile Testing Cloud Guide for Android and iOS

BitBar: Mobile Testing Cloud Guide for Android and iOS

BitBar is a mobile device testing cloud now owned by SmartBear. It provides real Android and iOS devices for automated and manual testing, with strong Appium support and integration with popular CI/CD tools. If your team uses other SmartBear products (ReadyAPI, TestComplete), BitBar fits naturally into that ecosystem.

This guide covers BitBar's features, how to write tests against it, and how to build it into a CI pipeline.

What BitBar Provides

Real device cloud: 300+ real Android and iOS devices across hardware models and OS versions.

Desktop browser testing: BitBar also hosts desktop browsers (Chrome, Firefox, Safari, Edge) — cross-platform testing from one platform.

Test frameworks supported:

  • Appium (Java, Python, Ruby, JavaScript, C#)
  • XCTest / XCUITest
  • Espresso
  • Calabash
  • Custom frameworks via client-side execution

Execution modes:

  • Server-side execution — upload your test APK and app APK; BitBar runs them on its infrastructure
  • Client-side execution — your CI machine drives the test; BitBar provides remote device access

Client-Side Appium Setup

The most flexible mode: your test code runs locally or in CI, connecting to BitBar's devices remotely.

from appium import webdriver
from appium.options import AppiumOptions
import os

options = AppiumOptions()

# BitBar authentication
options.set_capability("bitbar_apiKey", os.environ["BITBAR_API_KEY"])

# Device selection
options.set_capability("bitbar_device", "Samsung Galaxy S23")
# Or use a device group:
options.set_capability("bitbar_deviceGroup", "my-device-group")
# Or OS filter (allocates any matching available device):
# Specify via bitbar_device or combine with platform caps

# App — use BitBar app ID after uploading
options.set_capability("bitbar_app", 123456)

# Standard Appium capabilities
options.set_capability("platformName", "Android")
options.set_capability("automationName", "UIAutomator2")
options.set_capability("appPackage", "com.yourapp")
options.set_capability("appActivity", "com.yourapp.MainActivity")
options.set_capability("newCommandTimeout", 120)

driver = webdriver.Remote(
    command_executor="https://appium.bitbar.com/wd/hub",
    options=options
)

iOS Appium

options.set_capability("bitbar_apiKey", os.environ["BITBAR_API_KEY"])
options.set_capability("bitbar_device", "Apple iPhone 15 Pro")
options.set_capability("bitbar_app", 789012)  # IPA uploaded to BitBar
options.set_capability("platformName", "iOS")
options.set_capability("automationName", "XCUITest")
options.set_capability("bundleId", "com.yourapp.ios")

driver = webdriver.Remote(
    command_executor="https://appium.bitbar.com/wd/hub",
    options=options
)

Uploading Apps

# Upload Android APK
curl -X POST "https://cloud.bitbar.com/api/me/files" \
  -H "Authorization: Bearer $BITBAR_API_KEY" \
  -F "file=@app-debug.apk"
# Returns: {"id": 123456, "name": "app-debug.apk"}

# Upload iOS IPA
curl -X POST "https://cloud.bitbar.com/api/me/files" \
  -H "Authorization: Bearer $BITBAR_API_KEY" \
  -F "file=@MyApp.ipa"

Use the returned id as bitbar_app in your Appium capabilities.

Listing Available Devices

# Get all available devices
curl "https://cloud.bitbar.com/api/v2/devices" \
  -H "Authorization: Bearer $BITBAR_API_KEY" \
  | jq '.data[] | {id, displayName, osType, osVersion}'

# Filter by OS
curl "https://cloud.bitbar.com/api/v2/devices?filter=osType_EQ_ANDROID" \
  -H "Authorization: Bearer $BITBAR_API_KEY"

Writing Tests

A complete pytest example:

# conftest.py
import pytest
from appium import webdriver
from appium.options import AppiumOptions
import os

BITBAR_ENDPOINT = "https://appium.bitbar.com/wd/hub"

def make_driver(device_name: str, app_id: int, platform: str = "Android"):
    options = AppiumOptions()
    options.set_capability("bitbar_apiKey", os.environ["BITBAR_API_KEY"])
    options.set_capability("bitbar_device", device_name)
    options.set_capability("bitbar_app", app_id)
    options.set_capability("platformName", platform)
    
    if platform == "Android":
        options.set_capability("automationName", "UIAutomator2")
        options.set_capability("appPackage", os.environ["APP_PACKAGE"])
        options.set_capability("appActivity", os.environ["APP_ACTIVITY"])
    else:
        options.set_capability("automationName", "XCUITest")
        options.set_capability("bundleId", os.environ["BUNDLE_ID"])
    
    options.set_capability("newCommandTimeout", 180)
    options.set_capability("autoGrantPermissions", True)
    
    return webdriver.Remote(
        command_executor=BITBAR_ENDPOINT,
        options=options
    )

@pytest.fixture(scope="function")
def android_driver():
    driver = make_driver(
        "Samsung Galaxy S23",
        int(os.environ["BITBAR_APP_ID"])
    )
    yield driver
    driver.quit()

@pytest.fixture(scope="function")
def ios_driver():
    driver = make_driver(
        "Apple iPhone 15 Pro",
        int(os.environ["BITBAR_IOS_APP_ID"]),
        platform="iOS"
    )
    yield driver
    driver.quit()
# tests/test_onboarding.py
from appium.webdriver.common.appiumby import AppiumBy

def test_onboarding_skip(android_driver):
    driver = android_driver
    
    # Skip tutorial
    skip = driver.find_element(AppiumBy.ID, "com.yourapp:id/skip_button")
    skip.click()
    
    # Verify home screen
    home = driver.find_element(AppiumBy.ID, "com.yourapp:id/home_feed")
    assert home.is_displayed()

def test_ios_onboarding_skip(ios_driver):
    driver = ios_driver
    
    skip = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "Skip Tutorial")
    skip.click()
    
    home = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "Home Feed")
    assert home.is_displayed()

CI/CD Integration

GitHub Actions

name: BitBar Mobile Tests
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  android-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build APK
        run: ./gradlew assembleDebug
      
      - name: Upload APK to BitBar
        run: |
          RESPONSE=$(curl -s -X POST \
            "https://cloud.bitbar.com/api/me/files" \
            -H "Authorization: Bearer ${{ secrets.BITBAR_API_KEY }}" \
            -F "file=@app/build/outputs/apk/debug/app-debug.apk")
          echo "BITBAR_APP_ID=$(echo $RESPONSE | jq -r '.id')" >> $GITHUB_ENV
      
      - name: Run Tests
        env:
          BITBAR_API_KEY: ${{ secrets.BITBAR_API_KEY }}
          APP_PACKAGE: com.yourapp.debug
          APP_ACTIVITY: com.yourapp.MainActivity
        run: |
          pip install appium-python-client pytest pytest-xdist
          pytest tests/ \
            -v \
            -n 2 \
            --junit-xml=results/android-results.xml
      
      - name: Publish Results
        if: always()
        uses: EnricoMi/publish-unit-test-result-action@v2
        with:
          files: results/*.xml

Parallel Execution

Use pytest-xdist to run tests on multiple devices simultaneously:

# Run 4 tests in parallel
pytest tests/ -n 4

Each parallel worker gets its own driver with its own device session. BitBar allocates different devices automatically if the bitbar_device isn't fixed to a specific model — or you can configure each worker to use a different device.

Server-Side Execution (Batch Mode)

If your tests are bundled and you want BitBar to execute them without a CI machine driving them:

# Create a test run via API
curl -X POST "https://cloud.bitbar.com/api/me/runs" \
  -H "Authorization: Bearer $BITBAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "frameworkId": 1234,
    "osType": "ANDROID",
    "appId": 123456,
    "testId": 789012,
    "deviceGroupId": 56789,
    "timeout": 600
  }'

This mode is useful when you want BitBar to manage the execution environment entirely — no runner to maintain in CI.

Reading Test Reports

After each run, BitBar provides in the web portal:

  • Run overview — total pass/fail, device breakdown
  • Per-device logs — device log, Appium log, test framework output
  • Screenshots — captured at each test step
  • Video — full session recording
  • Performance data — CPU and memory graphs correlated with test timeline

Download results via API:

# Get run details
curl "https://cloud.bitbar.com/api/me/runs/{runId}" \
  -H "Authorization: Bearer $BITBAR_API_KEY"

# Get test results (JUnit XML)
curl "https://cloud.bitbar.com/api/me/runs/{runId}/files?filter=type_EQ_TEST_RESULTS" \
  -H "Authorization: Bearer $BITBAR_API_KEY"

Device Groups

Managing individual device names in tests is fragile — device names change and availability fluctuates. Device groups solve this:

  1. In BitBar portal: Device Groups > Create Group
  2. Add devices by model, OS version, or tags
  3. Reference the group in tests:
options.set_capability("bitbar_deviceGroup", "Android - Release Matrix")

BitBar selects an available device from the group for each session. If a device is busy, it queues until one is available.

BitBar vs. Alternatives

Factor BitBar AWS Device Farm Firebase Test Lab
SmartBear ecosystem Yes No No
Desktop browser testing Yes No No
Client-side Appium Yes Limited Yes
Server-side batch execution Yes Yes No
Price (approx) $99+/month Per-minute Per-hour
iOS coverage Good Strong Limited

BitBar is the best choice when you're already in the SmartBear ecosystem (ReadyAPI, TestComplete) or need desktop browser testing alongside mobile in one platform.

Common Issues

Test times out waiting for a device. Popular devices like Pixel 8 and Galaxy S23 are in high demand. Use device groups with multiple models so BitBar can pick whichever is available.

App crashes immediately on launch. Check that your APK/IPA is a debug build (or signed for distribution, for iOS). BitBar can't resign apps.

Appium version mismatch. BitBar's hosted Appium version may differ from what you test with locally. Specify the bitbar_appiumVersion capability to pin a version.

Session cleanup. Always call driver.quit() — open sessions consume concurrency slots and billing. Use try/finally blocks or pytest fixtures with proper teardown.

Summary

BitBar is a reliable mobile testing cloud with strong Appium support and a flexible client-side execution model. Its integration with the SmartBear ecosystem makes it a natural fit for enterprises already using ReadyAPI or TestComplete.

Start with client-side Appium execution (simplest to configure), upload your APK, and point at BitBar's Appium endpoint. Once the basics are running, add device groups and parallel execution to maximize coverage per CI run.

Read more

Start now free