---
title: Mobile App Instrumentation with Appium | TestingBot
description: Instrument mobile apps for testing with Appium. Perform image injection,
  biometric authentication, mock sms messages.
source_url:
  html: https://testingbot.com/support/app-automate/appium/instrumentation
  md: https://testingbot.com/support/app-automate/appium/instrumentation/index.md
---
# App Instrumentation with Appium

App instrumentation means adding extra hooks to your app while it runs on TestingBot's devices. It lets your automated tests interact with things that normally require human interaction, such as authentication, taking a specific photo or making a call.

With app instrumentation, you can perform the following tasks in an automated Appium test script:

- [Inject images into the camera](https://testingbot.com#image-injection): feed a test image to the virtual camera instead of using a real one.
- [Biometric authentication](https://testingbot.com#biometric): simulate fingerprint or Touch ID prompts in your tests.
- [Receive calls and SMS messages](https://testingbot.com#calls-sms): emulate incoming phone calls or text messages to see how your app responds.

## Injecting images into camera
Android Emulators Only

Image injection allows you to specify a base64 encoded image to the virtual camera of the Android emulator.

The test script will fetch the content of the image, convert it to base64 and send it to the TestingBot grid. The image will be used by the remote device to inject into the camera.

Make sure to include the `images` Appium plugin, as it is required for this to function correctly.

[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#)

    import io.appium.java_client.AppiumDriver;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import java.net.URL;
    import java.util.Base64;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.util.HashMap;
    
    public class ImageInjectionExample {
        public static String imageToBase64(String url) throws Exception {
            byte[] data = java.net.URI.create(url).toURL().openStream().readAllBytes();
            return Base64.getEncoder().encodeToString(data);
        }
    
        public static void main(String[] args) throws Exception {
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("platformName", "Android");
            caps.setCapability("browserName", "chrome");
            caps.setCapability("browserVersion", "15");
            caps.setCapability("appium:deviceName", "Pixel 9");
            caps.setCapability("tb:appiumPlugins", new String[]{"images"});
            caps.setCapability("tb:appiumVersion", "2.11.3");
            caps.setCapability("appium:injectedImageProperties", new HashMap<>());
    
            AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);
    
            String base64Image = imageToBase64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png");
            driver.executeScript("mobile: injectEmulatorCameraImage", new HashMap<String, Object>() {{
                put("payload", base64Image);
            }});
    
            Thread.sleep(30000);
    
            base64Image = imageToBase64("https://testingbot.com/assets/about.png");
            driver.executeScript("mobile: injectEmulatorCameraImage", new HashMap<String, Object>() {{
                put("payload", base64Image);
            }});
    
            Thread.sleep(30000);
            driver.quit();
        }
    }

    const { remote } = require('webdriverio');
    const fs = require('fs');
    const fetch = require('node-fetch');
    
    async function imageToBase64(url) {
      const res = await fetch(url);
      const buffer = await res.buffer();
      return buffer.toString('base64');
    }
    
    (async () => {
      const caps = {
        platformName: 'Android',
        'appium:deviceName': 'Pixel 9',
        browserName: 'chrome',
        browserVersion: '15',
        'tb:options': { 'appiumVersion': '2.11.3', 'appiumPlugins': ['images'] },
        'appium:injectedImageProperties': {}
      };
    
      const driver = await remote({
        protocol: 'https',
        hostname: 'hub.testingbot.com',
        port: 443,
        path: '/wd/hub',
        user: 'key',
        key: 'secret',
        capabilities: caps
      });
    
      let base64Image = await imageToBase64('https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png');
      await driver.executeScript('mobile: injectEmulatorCameraImage', [{ payload: base64Image }]);
    
      console.log("Injected first image");
      await driver.pause(30000);
    
      base64Image = await imageToBase64('https://testingbot.com/assets/about.png');
      await driver.executeScript('mobile: injectEmulatorCameraImage', [{ payload: base64Image }]);
    
      console.log("Injected second image");
      await driver.pause(30000);
    
      await driver.deleteSession();
    })();

    from appium import webdriver
    import base64
    import requests
    import time
    
    def image_to_base64(url):
        response = requests.get(url)
        return base64.b64encode(response.content).decode('utf-8')
    
    caps = {
        "platformName": "Android",
        "browserName": "chrome",
        "browserVersion": "15",
        "appium:deviceName": "Pixel 9",
        "tb:appiumPlugins": ["images"],
        "tb:appiumVersion": "2.11.3",
        "appium:injectedImageProperties": {}
    }
    
    driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)
    
    base64_image = image_to_base64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png")
    driver.execute_script("mobile: injectEmulatorCameraImage", { "payload": base64_image })
    
    time.sleep(30)
    print("Changing image")
    
    base64_image = image_to_base64("https://testingbot.com/assets/about.png")
    driver.execute_script("mobile: injectEmulatorCameraImage", { "payload": base64_image })
    
    time.sleep(30)
    driver.quit()

    #!/usr/bin/env ruby
    require 'rubygems'
    require 'appium_lib'
    require 'base64'
    require 'open-uri'
    
    def image_to_base64(image_url)
      image_data = URI.parse(image_url).open.read
      Base64.strict_encode64(image_data)
    end
    
    caps = {
      "browserName" => "chrome",
      "browserVersion" => "15",
      "appium:deviceName" => "Pixel 9",
      "platformName" => "Android",
      "tb:appiumPlugins" => ["images"],
      "tb:appiumVersion" => "2.11.3",
      "appium:injectedImageProperties" => {}
    }
    
    appium_driver = Appium::Driver.new({
      caps: caps,
      appium_lib: {
        server_url: "https://key:secret@hub.testingbot.com/wd/hub"
      }
    }, true)
    
    driver = appium_driver.start_driver
    
    base64_image = image_to_base64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png")
    driver.execute_script('mobile: injectEmulatorCameraImage', { payload: base64_image })
    
    sleep 30
    puts "Changing image"
    
    base64_image = image_to_base64("https://testingbot.com/assets/about.png")
    driver.execute_script('mobile: injectEmulatorCameraImage', { payload: base64_image })
    
    sleep 30
    driver.quit

    using OpenQA.Selenium;
    using OpenQA.Selenium.Appium;
    using OpenQA.Selenium.Remote;
    using System;
    using System.Net.Http;
    using System.Threading.Tasks;
    
    class ImageInjectionExample
    {
        static async Task<string> ImageToBase64(string url)
        {
            using (HttpClient client = new HttpClient())
            {
                var data = await client.GetByteArrayAsync(url);
                return Convert.ToBase64String(data);
            }
        }
    
        static async Task Main(string[] args)
        {
            var options = new AppiumOptions();
            options.PlatformName = "Android";
            options.AddAdditionalAppiumOption("browserName", "chrome");
            options.AddAdditionalAppiumOption("browserVersion", "15");
            options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 9");
            options.AddAdditionalAppiumOption("tb:appiumPlugins", new string[] { "images" });
            options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3");
            options.AddAdditionalAppiumOption("appium:injectedImageProperties", new { });
    
            var driver = new RemoteWebDriver(
                new Uri("https://key:secret@hub.testingbot.com/wd/hub"),
                options
            );
    
            var base64Image = await ImageToBase64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png");
            driver.ExecuteScript("mobile: injectEmulatorCameraImage", new Dictionary<string, object> { { "payload", base64Image } });
    
            Console.WriteLine("Injected first image");
            System.Threading.Thread.Sleep(30000);
    
            base64Image = await ImageToBase64("https://testingbot.com/assets/about.png");
            driver.ExecuteScript("mobile: injectEmulatorCameraImage", new Dictionary<string, object> { { "payload", base64Image } });
    
            Console.WriteLine("Injected second image");
            System.Threading.Thread.Sleep(30000);
    
            driver.Quit();
        }
    }

## Biometric authentication (Finger Print, Touch Id)

### Android fingerprint authentication

Emulate fingerprints on Android Emulator, with the [mobile:fingerprint](https://github.com/appium/appium-uiautomator2-driver?tab=readme-ov-file#mobile-fingerprint) command. Only works on API 23+ with [Appium version 2 or higher](https://testingbot.com/support/app-automate/appium/appium-versions).

[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#)

    import io.appium.java_client.AppiumDriver;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import java.net.URL;
    import java.util.HashMap;
    
    public class FingerprintExample {
        public static void main(String[] args) throws Exception {
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("platformName", "Android");
            caps.setCapability("appium:deviceName", "Pixel 9");
            caps.setCapability("browserName", "chrome");
            caps.setCapability("browserVersion", "15");
            caps.setCapability("tb:appiumVersion", "2.11.3");
    
            AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);
    
            HashMap<String, Object> args1 = new HashMap<>();
            args1.put("fingerprintId", 1);
            driver.executeScript("mobile: fingerprint", args1);
    
            Thread.sleep(5000);
            driver.quit();
        }
    }

    const { remote } = require('webdriverio');
    
    (async () => {
      const caps = {
        platformName: 'Android',
        'appium:deviceName': 'Pixel 9',
        browserName: 'chrome',
        browserVersion: '15',
        'tb:appiumVersion': '2.11.3'
      };
    
      const driver = await remote({
        protocol: 'https',
        hostname: 'hub.testingbot.com',
        port: 443,
        path: '/wd/hub',
        user: 'key',
        key: 'secret',
        capabilities: caps
      });
    
      await driver.executeScript('mobile: fingerprint', [{ fingerprintId: 1 }]);
      await driver.pause(5000);
    
      await driver.deleteSession();
    })();

    from appium import webdriver
    import time
    
    caps = {
        "platformName": "Android",
        "appium:deviceName": "Pixel 9",
        "browserName": "chrome",
        "browserVersion": "15",
        "tb:appiumVersion": "2.11.3"
    }
    
    driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)
    
    # Simulate fingerprint auth with ID 1
    driver.execute_script("mobile: fingerprint", { "fingerprintId": 1 })
    
    time.sleep(5)
    driver.quit()

    require 'appium_lib'
    
    caps = {
      "platformName" => "Android",
      "appium:deviceName" => "Pixel 9",
      "browserName" => "chrome",
      "browserVersion" => "15",
      "tb:appiumVersion" => "2.11.3"
    }
    
    driver = Appium::Driver.new({
      caps: caps,
      appium_lib: {
        server_url: "https://key:secret@hub.testingbot.com/wd/hub"
      }
    }, true).start_driver
    
    driver.execute_script("mobile: fingerprint", { fingerprintId: 1 })
    sleep 5
    
    driver.quit

    using OpenQA.Selenium.Remote;
    using System;
    using System.Collections.Generic;
    using OpenQA.Selenium.Appium;
    
    class FingerprintExample {
        static void Main(string[] args) {
            var options = new AppiumOptions();
            options.PlatformName = "Android";
            options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 9");
            options.AddAdditionalAppiumOption("browserName", "chrome");
            options.AddAdditionalAppiumOption("browserVersion", "15");
            options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3");
    
            var driver = new RemoteWebDriver(
                new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options);
    
            driver.ExecuteScript("mobile: fingerprint", new Dictionary<string, object> {
                { "fingerprintId", 1 }
            });
    
            System.Threading.Thread.Sleep(5000);
            driver.Quit();
        }
    }

### iOS TouchID/FaceID authentication

You can simulate a biometric match/non-match event with TouchID and FaceID, with the [mobile: sendBiometricMatch](https://appium.github.io/appium-xcuitest-driver/latest/reference/execute-methods/#mobile-sendbiometricmatch) command.

[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#)

    import io.appium.java_client.AppiumDriver;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import java.net.URL;
    import java.util.HashMap;
    
    public class TouchIDExample {
        public static void main(String[] args) throws Exception {
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("platformName", "iOS");
            caps.setCapability("appium:deviceName", "iPhone 15");
            caps.setCapability("appium:platformVersion", "18.0");
            caps.setCapability("browserName", "safari");
            caps.setCapability("tb:appiumVersion", "2.11.3");
    
            AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);
    
            HashMap<String, Object> args1 = new HashMap<>();
            args1.put("type", "touchId");
            args1.put("match", true);
            driver.executeScript("mobile: sendBiometricMatch", args1);
    
            Thread.sleep(5000);
    
            HashMap<String, Object> args2 = new HashMap<>();
            args2.put("type", "touchId");
            args2.put("match", false);
            driver.executeScript("mobile: sendBiometricMatch", args2);
    
            Thread.sleep(5000);
            driver.quit();
        }
    }

    const { remote } = require('webdriverio');
    
    (async () => {
      const caps = {
        platformName: 'iOS',
        'appium:deviceName': 'iPhone 15',
        'appium:platformVersion': '18.0',
        browserName: 'safari',
        'tb:appiumVersion': '2.11.3'
      };
    
      const driver = await remote({
        protocol: 'https',
        hostname: 'hub.testingbot.com',
        port: 443,
        path: '/wd/hub',
        user: 'key',
        key: 'secret',
        capabilities: caps
      });
    
      // Successful Touch ID
      await driver.executeScript('mobile: sendBiometricMatch', [{ type: 'touchId', match: true }]);
      await driver.pause(5000);
    
      // Failed Touch ID
      await driver.executeScript('mobile: sendBiometricMatch', [{ type: 'touchId', match: false }]);
      await driver.pause(5000);
    
      await driver.deleteSession();
    })();

    from appium import webdriver
    import time
    
    caps = {
        "platformName": "iOS",
        "appium:deviceName": "iPhone 15",
        "appium:platformVersion": "18.0",
        "browserName": "safari",
        "tb:appiumVersion": "2.11.3"
    }
    
    driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)
    
    # Successful Touch ID
    driver.execute_script("mobile: sendBiometricMatch", { "type": "touchId", "match": True })
    time.sleep(5)
    
    # Failed Touch ID
    driver.execute_script("mobile: sendBiometricMatch", { "type": "touchId", "match": False })
    time.sleep(5)
    
    driver.quit()

    require 'appium_lib'
    
    caps = {
      "platformName" => "iOS",
      "appium:deviceName" => "iPhone 15",
      "appium:platformVersion" => "18.0",
      "browserName" => "safari",
      "tb:appiumVersion" => "2.11.3"
    }
    
    driver = Appium::Driver.new({
      caps: caps,
      appium_lib: {
        server_url: "https://key:secret@hub.testingbot.com/wd/hub"
      }
    }, true).start_driver
    
    # Success
    driver.execute_script("mobile: sendBiometricMatch", { type: "touchId", match: true })
    sleep 5
    
    # Failure
    driver.execute_script("mobile: sendBiometricMatch", { type: "touchId", match: false })
    sleep 5
    
    driver.quit

    using OpenQA.Selenium.Remote;
    using System;
    using System.Collections.Generic;
    using OpenQA.Selenium.Appium;
    
    class TouchIDExample {
        static void Main(string[] args) {
            var options = new AppiumOptions();
            options.PlatformName = "iOS";
            options.AddAdditionalAppiumOption("appium:deviceName", "iPhone 15");
            options.AddAdditionalAppiumOption("appium:platformVersion", "18.0");
            options.AddAdditionalAppiumOption("browserName", "safari");
            options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3");
    
            var driver = new RemoteWebDriver(
                new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options);
    
            driver.ExecuteScript("mobile: sendBiometricMatch", new Dictionary<string, object> {
                { "type", "touchId" },
                { "match", true }
            });
    
            System.Threading.Thread.Sleep(5000);
    
            driver.ExecuteScript("mobile: sendBiometricMatch", new Dictionary<string, object> {
                { "type", "touchId" },
                { "match", false }
            });
    
            System.Threading.Thread.Sleep(5000);
            driver.Quit();
        }
    }

## Receiving calls and text messages (SMS)

You can simulate an incoming call or text message with Appium. Please see the examples below.

[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#)

    import io.appium.java_client.AppiumDriver;
    import io.appium.java_client.android.AndroidDriver;
    import io.appium.java_client.android.connection.GsmCallActions;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import java.net.URL;
    
    public class AndroidGsmExample {
        public static void main(String[] args) throws Exception {
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("platformName", "Android");
            caps.setCapability("appium:deviceName", "Pixel 9");
            caps.setCapability("browserName", "chrome");
            caps.setCapability("browserVersion", "15");
            caps.setCapability("tb:appiumVersion", "2.11.3");
    
            AndroidDriver driver = new AndroidDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);
    
            // Send SMS
            driver.sendSMS("5555555555", "Your message here!");
    
            // Make and handle a phone call
            driver.makeGsmCall("5555555555", GsmCallActions.CALL);
            Thread.sleep(2000);
            driver.makeGsmCall("5555555555", GsmCallActions.ACCEPT);
            Thread.sleep(2000);
            driver.makeGsmCall("5555555555", GsmCallActions.CANCEL);
    
            driver.quit();
        }
    }

    const { remote } = require('webdriverio');
    
    (async () => {
      const caps = {
        platformName: 'Android',
        'appium:deviceName': 'Pixel 9',
        browserName: 'chrome',
        browserVersion: '15',
        'tb:appiumVersion': '2.11.3'
      };
    
      const driver = await remote({
        protocol: 'https',
        hostname: 'hub.testingbot.com',
        port: 443,
        path: '/wd/hub',
        user: 'key',
        key: 'secret',
        capabilities: caps
      });
    
      // Send SMS
      await driver.sendSms('5555555555', 'Your message here!');
    
      // Phone call
      await driver.makeGsmCall('5555555555', 'call');
      await driver.pause(2000);
      await driver.makeGsmCall('5555555555', 'accept');
      await driver.pause(2000);
      await driver.makeGsmCall('5555555555', 'cancel');
    
      await driver.deleteSession();
    })();

    from appium import webdriver
    import time
    
    caps = {
        "platformName": "Android",
        "appium:deviceName": "Pixel 9",
        "browserName": "chrome",
        "browserVersion": "15",
        "tb:appiumVersion": "2.11.3"
    }
    
    driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)
    
    # Send SMS
    driver.send_sms("5555555555", "Your message here!")
    
    # Phone call
    driver.make_gsm_call("5555555555", "call")
    time.sleep(2)
    driver.make_gsm_call("5555555555", "accept")
    time.sleep(2)
    driver.make_gsm_call("5555555555", "cancel")
    
    driver.quit()

    require 'appium_lib'
    
    caps = {
      "platformName" => "Android",
      "appium:deviceName" => "Pixel 9",
      "browserName" => "chrome",
      "browserVersion" => "15",
      "tb:appiumVersion" => "2.11.3"
    }
    
    driver = Appium::Driver.new({
      caps: caps,
      appium_lib: {
        server_url: "https://key:secret@hub.testingbot.com/wd/hub"
      }
    }, true).start_driver
    
    # Send SMS
    driver.send_sms("5555555555", "Your message here!")
    
    # Phone call
    driver.make_gsm_call("5555555555", "call")
    sleep 2
    driver.make_gsm_call("5555555555", "accept")
    sleep 2
    driver.make_gsm_call("5555555555", "cancel")
    
    driver.quit

    using OpenQA.Selenium.Remote;
    using OpenQA.Selenium.Appium;
    using OpenQA.Selenium.Appium.Android;
    using System;
    
    class AndroidGsmExample {
        static void Main(string[] args) {
            var options = new AppiumOptions();
            options.PlatformName = "Android";
            options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 9");
            options.AddAdditionalAppiumOption("browserName", "chrome");
            options.AddAdditionalAppiumOption("browserVersion", "15");
            options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3");
    
            var driver = new AndroidDriver(new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options);
    
            // Send SMS
            driver.SendSMS("5555555555", "Your message here!");
    
            // Phone call
            driver.MakeGsmCall("5555555555", "call");
            System.Threading.Thread.Sleep(2000);
            driver.MakeGsmCall("5555555555", "accept");
            System.Threading.Thread.Sleep(2000);
            driver.MakeGsmCall("5555555555", "cancel");
    
            driver.Quit();
        }
    }

### Looking for more help?

Have questions or need more information? Reach out via email or Slack.

[Email us](https://testingbot.com/contact/new)[Slack Join our Slack](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw)
