---
title: Browser Extension Testing with Selenium WebDriver
description: How to run Selenium WebDriver tests with Chrome, Firefox, Edge and Safari
  extensions
source_url:
  html: https://testingbot.com/support/web-automate/selenium/browser-extension
  md: https://testingbot.com/support/web-automate/selenium/browser-extension/index.md
---
# Browser Extension

While running Automated tests, you might want to have a browser extension installed. Below you can find information on how to add a browser extension to a Chrome, Firefox, Edge or Safari browser running in the TestingBot cloud.

To get started, make sure you have the extension file ready, then upload it either to a public URL or use the [TestingBot Storage](https://testingbot.com#storage).

Once you have a URL, you can specify the `load-extension` capability. This will instruct the remote TestingBot browsers to download the extension and add it to the browser at startup.

Example:

    "load-extension" : "https://..."

Example (Selenium 4):

    "tb:options" : {
      "load-extension" : "https://..."
    }

| Browser | Supported Format(s) | Example |
| --- | --- | --- |
| [Chrome](https://testingbot.com#chrome) | 
- `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) 
- `.crx` file 

 | 
- `https://.../extension.zip`
- `tb://sample-extension`

 |
| [Firefox](https://testingbot.com#firefox) | 
- `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, `lib/ directory`, ...) 
- `.xpi` file 

 | 
- `https://.../extension.zip`
- `tb://sample-extension`

 |
| [Edge](https://testingbot.com#edge) | 
- `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) 
- `.crx` file 

 | 
- `https://.../extension.zip`
- `tb://sample-extension`

 |
| [Safari & Safari Technology Preview](https://testingbot.com#safari) | 
- Test (Unsigned) Safari Web/App Extensions bundled in a zip file
- `.safariextz` file for Safari \<= 12

 | 
- `https://.../extension.zip`
- `tb://sample-extension`

 |

## TestingBot Storage

With [TestingBot Storage](https://testingbot.com/support/api#upload), you can upload your extensions to the TestingBot servers.   
 The advantage of this is that our test VMs can immediately download your extension from the TestingBot network, which is much faster than downloading from the public internet.

The API call will return a unique identifier, similar to `tb://efe932jfk`.   
 You can then use this identifier with the capability: `"load-extension" : "tb://..."`

## Chrome Browser Extension Testing

Once you've specified `"load-extension"`, the Chrome browser will start up with the extension preloaded. You can now run your Selenium tests while the extension is active on the remote browser.

### UI Testing Chrome Extensions

To test the UI of your Chrome extension, you can have your Selenium test navigate to a `chrome-extension://` URL.   
 For example, if the ID of your addon is `paaamahlcokbnafoiahanekijojkhbdm`, you can navigate to `chrome-extension://paaamahlcokbnafoiahanekijojkhbdm`.

Please see the NodeJS example below for a complete rundown on how to test the UI of your Chrome extension:

    const webdriver = require('selenium-webdriver');
    const capabilities = {
      'platformName': 'WIN10',
      'browserName': 'chrome',
      'browserVersion': 'latest',
      'tb:options': {
        'load-extension': 'https://...path..to..extension'
      }
    };
    async function runTest () {
      let driver = new webdriver.Builder()
        .usingServer('https://api_key:api_secret@hub.testingbot.com/wd/hub')
        .withCapabilities(capabilities)
        .build();
      await driver.get('chrome-extension://paaamahlcokbnafoiahanekijojkhbdm/popup/index.html');
      const element = await driver.findElement(By.css('#environments'));
      const isElementDisplayed = await element.isDisplayed();
      if (isElementDisplayed) {
        console.log('Element is present on the page.');
      } else {
        console.log('Element is not present on the page.');
      }
      await driver.quit();
    }
    runTest();

## Firefox Browser Extension Testing

You can specify the URL to a `xpi` file in the `load-extension` capability. This will make sure the Firefox browser has the extension installed (as a temporary extension) at the start of the Selenium test.

### UI Testing Firefox Extensions

If you want to test the UI of your Firefox extension, the `moz-extension://` URL, you will need to specify the extension ID in the URL.   
 Because TestingBot installs the extension as a temporary extension, the id will always be different as it is generated as a random uuid(4).

TestingBot provides a capability to hardcode your Firefox exension to a fixed uuid which you've generated, by using the `firefoxExtensionMap` capability. To use this, you could set the ID in the `manifest.json` of the extension:

    "browser_specific_settings": {
      "gecko": {
        "id": "addon@testingbot.com",
        "strict_min_version": "109.0"
      }
    }

You can now link the gecko id to a uuid you've generated:

    const webdriver = require('selenium-webdriver');
    const capabilities = {
      'platformName': 'WIN10',
      'browserName': 'firefox',
      'browserVersion': 'latest',
      'tb:options': {
        'load-extension': 'https://...path..to..extension',
        'firefoxExtensionMap': {
          'addon@testingbot.com': '3d9b1639-77fb-44a1-888a-6d97d773e96b'
        }
      }
    };
    async function runTest () {
      let driver = new webdriver.Builder()
        .usingServer('https://api_key:api_secret@hub.testingbot.com/wd/hub')
        .withCapabilities(capabilities)
        .build();
      await driver.get('moz-extension://3d9b1639-77fb-44a1-888a-6d97d773e96b/popup/index.html');
      const element = await driver.findElement(By.css('#environments'));
      const isElementDisplayed = await element.isDisplayed();
      if (isElementDisplayed) {
        console.log('Element is present on the page.');
      } else {
        console.log('Element is not present on the page.');
      }
      await driver.quit();
    }
    runTest();

## Edge Browser Extension Testing

Once you've specified `"load-extension"`, the Edge browser will start up with the extension preloaded. You can now run your Selenium tests while the extension is active on the remote Edge browser.

### UI Testing Edge Extensions

To test the UI of your Edge extension, you can have your Selenium test navigate to a `chrome-extension://` or `extension://` URL.   
 For example, if the ID of your addon is `paaamahlcokbnafoiahanekijojkhbdm`, you can navigate to `extension://paaamahlcokbnafoiahanekijojkhbdm`.

Please see the NodeJS example below for a complete rundown on how to test the UI of your Edge extension:

    const webdriver = require('selenium-webdriver');
    const capabilities = {
      'platformName': 'WIN10',
      'browserName': 'microsoftedge',
      'browserVersion': 'latest',
      'tb:options': {
        'load-extension': 'https://...path..to..extension'
      }
    };
    async function runTest () {
      let driver = new webdriver.Builder()
        .usingServer('https://api_key:api_secret@hub.testingbot.com/wd/hub')
        .withCapabilities(capabilities)
        .build();
      await driver.get('extension://paaamahlcokbnafoiahanekijojkhbdm/popup/index.html');
      const element = await driver.findElement(By.css('#environments'));
      const isElementDisplayed = await element.isDisplayed();
      if (isElementDisplayed) {
        console.log('Element is present on the page.');
      } else {
        console.log('Element is not present on the page.');
      }
      await driver.quit();
    }
    runTest();

## Safari Extension Testing
Safari 16 and higher only

TestingBot allows you to upload a zip file containing your (unsigned) Safari Web Extension or Safari App Extension. Simply provide a URL to a zip file containing the extension, or upload the zip file on [TestingBot Storage](https://testingbot.com#storage).

You can now specify the URL to this file in the `load-extension` capability. When your test starts on a remote Safari instance, the extension will be enabled by default.

TestingBot provides Safari Technology Preview as well, allowing you to test on the upcoming new Safari version. You can use the same extension testing features, simply change the `version` to `dev`.

### Safari Extension Automation

TestingBot will automatically install and enable the extension in the Safari browser. Permissions will be granted automatically for the extension to access all webpages during the test.

 ![Safari permissions](https://testingbot.com/assets/support/web-automate/selenium/browser-extension/permissions-9541cd4aa43649ed64627925d68b08972d5267c39bea3823426fdb88ad7d6e49.png)
### Temporary Extension Installation

[Since Safari 18.4](https://webkit.org/blog/16574/webkit-features-in-safari-18-4/#web-extensions) you can temporarily install web extensions, without having to build it with Xcode. You can simply zip your web extension and TestingBot will automatically install it as a temporary extension.

You can try it on TestingBot's macOS Sequoia and macOS Tahoe machines.

The zip file could contain for example following 4 files: `background.js`, `content.js`, `manifest.json` and `page.js`.

### UI Testing Safari Extensions

To test the UI of your Safari extension, you will need to know the `safari-web-extension://` or `safari-app-extension://` URI. As Safari can change this to a random UUID, you will need to use the `tb:getExtensionId` command in your test to determine the correct URI to use.

Safaridriver currently contains a bug that does not detect the load completion of a `safari-web-extension://` request. To work around this, set the [pageLoad](https://www.w3.org/TR/webdriver2/#timeouts) timeout to a low value and catch any timeout error.

Please see the examples below on how to run a UI test against a Safari Web/App Extension:

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

    import org.openqa.selenium.*;
    import org.openqa.selenium.remote.*;
    import java.net.URL;
    import java.util.*;
    
    public class SafariExtensionTest {
      public static void main(String[] args) throws Exception {
        MutableCapabilities caps = new MutableCapabilities();
        caps.setCapability("browserName", "safari");
        caps.setCapability("browserVersion", "18.0");
        caps.setCapability("platformName", "SEQUOIA");
    
        Map<String, Object> tbOptions = new HashMap<>();
        tbOptions.put("load-extension", "tb://...safari-extension-path...");
        caps.setCapability("tb:options", tbOptions);
    
        WebDriver driver = new RemoteWebDriver(
          new URL("https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"),
          caps
        );
    
        driver.get("http://www.google.com/ncr");
        ((JavascriptExecutor) driver).executeScript("tb:setPageLoadTimeout", 5);
    
        String extensionId = (String) ((JavascriptExecutor) driver).executeScript("tb:getExtensionId");
        try {
          driver.get(extensionId + "popup/index.html");
        } catch (TimeoutException e) {
          System.out.println(e.getMessage());
        }
    
        System.out.println(driver.getPageSource());
        driver.quit();
      }
    }

    from selenium import webdriver
    from selenium.webdriver.safari.options import Options
    
    options = Options()
    options.set_capability("browserVersion", "18.0")
    options.set_capability("platformName", "SEQUOIA")
    options.set_capability("tb:options", {
        "load-extension": "tb://...safari-extension-path..."
    })
    
    driver = webdriver.Remote(
        command_executor="https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub",
        options=options
    )
    
    driver.get("http://www.google.com/ncr")
    driver.set_page_load_timeout(5)
    
    extension_id = driver.execute_script("tb:getExtensionId")
    
    try:
        driver.get(f"{extension_id}popup/index.html")
    except Exception as e:
        print(e)
    
    print(driver.page_source)
    driver.quit()

    const { Builder } = require("selenium-webdriver");
    
    (async () => {
      const caps = {
        browserName: "safari",
        browserVersion: "18.0",
        platformName: "SEQUOIA",
        "tb:options": {
          "load-extension": "tb://...safari-extension-path..."
        }
      };
    
      const driver = await new Builder()
        .usingServer("https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub")
        .withCapabilities(caps)
        .build();
    
      await driver.get("http://www.google.com/ncr");
      await driver.manage().setTimeouts({ pageLoad: 5000 });
    
      const extensionId = await driver.executeScript("tb:getExtensionId");
    
      try {
        await driver.get(`${extensionId}popup/index.html`);
      } catch (e) {
        console.log(e.message);
      }
    
      const pageSource = await driver.getPageSource();
      console.log(pageSource);
      await driver.quit();
    })();

    require 'selenium-webdriver'
    
    options = Selenium::WebDriver::Safari::Options.new
    options.browser_version = '18.0'
    options.platform_name = 'SEQUOIA'
    options.add_option('tb:options', {
      'load-extension': 'tb://...safari-extension-path...'
    })
    
    http_client = Selenium::WebDriver::Remote::Http::Default.new
    http_client.read_timeout = 300
    http_client.open_timeout = 300
    
    driver = Selenium::WebDriver.for(
      :remote,
      url: "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub",
      options: options,
      http_client: http_client
    )
    
    driver.navigate.to "http://www.google.com/ncr"
    driver.manage.timeouts.page_load = 5
    extension_id = driver.execute_script("tb:getExtensionId")
    
    begin
      driver.navigate.to "#{extension_id}popup/index.html"
    rescue => e
      puts e.message
    end
    
    puts driver.page_source
    driver.quit

    using OpenQA.Selenium;
    using OpenQA.Selenium.Remote;
    using OpenQA.Selenium.Safari;
    using System;
    using System.Collections.Generic;
    
    class SafariExtensionTest
    {
      static void Main()
      {
        var options = new SafariOptions();
        options.BrowserVersion = "18.0";
        options.PlatformName = "SEQUOIA";
        options.AddAdditionalOption("tb:options", new Dictionary<string, object>
        {
          { "load-extension", "tb://...safari-extension-path..." }
        });
    
        var driver = new RemoteWebDriver(
          new Uri("https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"),
          options
        );
    
        driver.Navigate().GoToUrl("http://www.google.com/ncr");
        driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);
    
        string extensionId = (string)((IJavaScriptExecutor)driver).ExecuteScript("tb:getExtensionId");
        try
        {
          driver.Navigate().GoToUrl(extensionId + "popup/index.html");
        }
        catch (WebDriverTimeoutException e)
        {
          Console.WriteLine(e.Message);
        }
    
        Console.WriteLine(driver.PageSource);
        driver.Quit();
      }
    }

### Older Safari versions

For Safari versions up to Safari 12, you can use a `.safariextz` format, in a `zip` file, to run and test Safari extensions.

## iOS Mobile Safari Browser Extension Testing

You can test your iOS Mobile Safari native extension with TestingBot. Simply upload your extension `.ipa` file to [TestingBot Storage](https://testingbot.com/support/api#upload) and use it in your capabilities:

    {
      "appium:app": "tb://path-to-mobile-safari-ext-ipa",
      "appium:includeSafariInWebviews": true,
      "appium:deviceName": "iPhone 16",
      "tb:options": {
        "realDevice": true
      }
    }

Next, you will need to allow this extension through the settings (preferences) app. Finally, we'll switch to the Safari app and change the context to Safari (WEBVIEW). Please see the examples below.

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

    import io.appium.java_client.AppiumBy;
    import io.appium.java_client.ios.IOSDriver;
    import io.appium.java_client.ios.options.XCUITestOptions;
    import org.openqa.selenium.WebElement;
    
    import java.net.URL;
    import java.util.Set;
    
    public class IOSAppiumAutomation {
        public static void main(String[] args) {
            try {
                XCUITestOptions options = new XCUITestOptions();
                options.setApp("tb://path-to-mobile-safari-ext-ipa");
                options.setDeviceName("iPhone 16");
                options.setCapability("appium:includeSafariInWebviews", true);
    
                java.util.Map<String, Object> tbOptions = new java.util.HashMap<>();
                tbOptions.put("realDevice", true);
                options.setCapability("tb:options", tbOptions);
    
                IOSDriver driver = new IOSDriver(
                    new URL("https://hub.testingbot.com/wd/hub"), options);
    
                // 1. Open Safari Settings via deep link
                driver.executeScript("mobile: deepLink",
                    java.util.Map.of("url", "app-prefs:com.apple.mobilesafari"));
    
                // 2. Tap "Extensions"
                WebElement extensionsCell = driver.findElement(
                    AppiumBy.iOSNsPredicateString("type == 'XCUIElementTypeCell' AND name == 'Extensions'"));
                extensionsCell.click();
    
                // 3. Tap your extension name
                WebElement extensionItem = driver.findElement(
                    AppiumBy.iOSNsPredicateString("type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'"));
                extensionItem.click();
    
                // 4. Toggle "Allow Extension"
                WebElement allowSwitch = driver.findElement(
                    AppiumBy.iOSNsPredicateString("type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'"));
                allowSwitch.click();
    
                // 5. Tap "All Websites"
                WebElement allWebsites = driver.findElement(
                    AppiumBy.iOSNsPredicateString("type == 'XCUIElementTypeCell' AND name == 'All Websites'"));
                allWebsites.click();
    
                // 6. Tap "Allow"
                WebElement allow = driver.findElement(
                    AppiumBy.iOSNsPredicateString("type == 'XCUIElementTypeCell' AND name == 'Allow'"));
                allow.click();
    
                // 7. Terminate Settings
                driver.executeScript("mobile: terminateApp",
                    java.util.Map.of("bundleId", "com.apple.Preferences"));
    
                // 8. Launch Safari
                driver.executeScript("mobile: launchApp",
                    java.util.Map.of("bundleId", "com.apple.mobilesafari"));
    
                // 9. Switch to WebView context
                Set<String> contexts = driver.getContextHandles();
                for (String context : contexts) {
                    if (context.contains("WEBVIEW")) {
                        driver.context(context);
                        break;
                    }
                }
    
                System.out.println("Finished automation steps.");
                driver.quit();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    from appium import webdriver
    from appium.options.ios import XCUITestOptions
    from appium.webdriver.common.appiumby import AppiumBy
    
    options = XCUITestOptions()
    options.app = "tb://path-to-mobile-safari-ext-ipa"
    options.device_name = "iPhone 16"
    options.set_capability("appium:includeSafariInWebviews", True)
    options.set_capability("tb:options", {"realDevice": True})
    
    driver = webdriver.Remote(
        command_executor='https://hub.testingbot.com/wd/hub',
        options=options
    )
    
    try:
        # 1. Open Safari settings via deep link
        driver.execute_script('mobile: deepLink', {
            'url': 'app-prefs:com.apple.mobilesafari'
        })
    
        # 2. Tap "Extensions"
        extensions_cell = driver.find_element(
            AppiumBy.IOS_PREDICATE,
            "type == 'XCUIElementTypeCell' AND name == 'Extensions'"
        )
        extensions_cell.click()
    
        # 3. Tap on your extension (e.g., "webrequest-har-collect")
        extension_item = driver.find_element(
            AppiumBy.IOS_PREDICATE,
            "type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'"
        )
        extension_item.click()
    
        # 4. Enable the switch "Allow Extension"
        allow_switch = driver.find_element(
            AppiumBy.IOS_PREDICATE,
            "type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'"
        )
        allow_switch.click()
    
        # 5. Tap "All Websites"
        all_websites = driver.find_element(
            AppiumBy.IOS_PREDICATE,
            "type == 'XCUIElementTypeCell' AND name == 'All Websites'"
        )
        all_websites.click()
    
        # 6. Tap "Allow"
        allow = driver.find_element(
            AppiumBy.IOS_PREDICATE,
            "type == 'XCUIElementTypeCell' AND name == 'Allow'"
        )
        allow.click()
    
        # 7. Terminate Settings app
        driver.execute_script('mobile: terminateApp', {
            'bundleId': 'com.apple.Preferences'
        })
    
        # 8. Launch Safari
        driver.execute_script('mobile: launchApp', {
            'bundleId': 'com.apple.mobilesafari'
        })
    
        # 9. Switch to WebView context
        contexts = driver.contexts
        webview = next((ctx for ctx in contexts if 'WEBVIEW' in ctx), None)
        if webview:
            driver.switch_to.context(webview)
    
        print("Finished automation steps.")
    
    finally:
        driver.quit()

    const { remote } = require('webdriverio');
    
    (async () => {
      const driver = await remote({
        path: 'https://hub.testingbot.com/wd/hub',
        port: 443,
        capabilities: {
          'appium:app': 'tb://path-to-mobile-safari-ext-ipa',
          platformName: 'iOS',
          'appium:automationName': 'XCUITest',
          'appium:includeSafariInWebviews': true,
          'appium:deviceName': 'iPhone 16',
          'tb:options': { realDevice: true }
        },
      });
    
      // 1. Open Safari settings via deep link
      await driver.execute('mobile: deepLink', {
        url: 'app-prefs:com.apple.mobilesafari',
      });
    
      // 2. Tap "Extensions"
      const extensionsCell = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'Extensions'`);
      await extensionsCell.waitForExist({ timeout: 10000 });
      await extensionsCell.click();
    
      // 3. Tap on your extension (e.g., "webrequest-har-collect")
      const extensionItem = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'`);
      await extensionItem.waitForExist({ timeout: 60000 });
      await extensionItem.click();
    
      // 4. Enable the switch "Allow Extension"
      const allowSwitch = await driver.$(`-ios predicate string:type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'`);
      await allowSwitch.waitForExist({ timeout: 60000 });
      await allowSwitch.click();
    
      // 5. Tap "All Websites"
      const allWebsites = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'All Websites'`);
      await allWebsites.waitForExist({ timeout: 60000 });
      await allWebsites.click();
    
      // 6. Tap "Allow"
      const allow = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'Allow'`);
      await allow.waitForExist({ timeout: 60000 });
      await allow.click();
    
      // 7. Terminate Settings app
      await driver.execute('mobile: terminateApp', {
        bundleId: 'com.apple.Preferences',
      });
    
      // 8. Launch Safari
      await driver.execute('mobile: launchApp', {
        bundleId: 'com.apple.mobilesafari',
      });
    
      // 9. Switch to WebView context
      const contexts = await driver.getContexts();
      const webview = contexts.find(ctx => ctx.includes('WEBVIEW'));
      if (webview) {
        await driver.switchContext(webview);
      }
    
      console.log('Finished automation steps.');
      await driver.deleteSession();
    })();

    require 'appium_lib'
    
    caps = {
      caps: {
        platformName: 'iOS',
        'appium:automationName': 'XCUITest',
        'appium:app': 'tb://path-to-mobile-safari-ext-ipa',
        'appium:deviceName': 'iPhone 16',
        'appium:includeSafariInWebviews': true,
        'tb:options': { 'realDevice' => true }
      },
      appium_lib: {
        server_url: 'https://hub.testingbot.com/wd/hub'
      }
    }
    
    driver = Appium::Driver.new(caps, true)
    driver.start_driver
    
    begin
      # 1. Open Safari settings via deep link
      driver.execute_script('mobile: deepLink', { url: 'app-prefs:com.apple.mobilesafari' })
    
      # 2. Tap "Extensions"
      extensions = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'Extensions'")
      extensions.click
    
      # 3. Tap your extension
      extension = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'")
      extension.click
    
      # 4. Enable "Allow Extension"
      allow_switch = driver.find_element(:predicate, "type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'")
      allow_switch.click
    
      # 5. Tap "All Websites"
      all_sites = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'All Websites'")
      all_sites.click
    
      # 6. Tap "Allow"
      allow = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'Allow'")
      allow.click
    
      # 7. Terminate Settings app
      driver.execute_script('mobile: terminateApp', { bundleId: 'com.apple.Preferences' })
    
      # 8. Launch Safari
      driver.execute_script('mobile: launchApp', { bundleId: 'com.apple.mobilesafari' })
    
      # 9. Switch to WebView context
      contexts = driver.available_contexts
      webview = contexts.find { |ctx| ctx.include?('WEBVIEW') }
      driver.set_context(webview) if webview
    
      puts 'Finished automation steps.'
    
    ensure
      driver.quit_driver
    end

    using OpenQA.Selenium;
    using OpenQA.Selenium.Appium;
    using OpenQA.Selenium.Appium.iOS;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    
    class Program
    {
        static void Main(string[] args)
        {
            var options = new AppiumOptions();
            options.PlatformName = "iOS";
            options.AutomationName = "XCUITest";
            options.AddAdditionalAppiumOption("app", "tb://path-to-mobile-safari-ext-ipa");
            options.AddAdditionalAppiumOption("deviceName", "iPhone 16");
            options.AddAdditionalAppiumOption("includeSafariInWebviews", true);
            options.AddAdditionalOption("tb:options", new Dictionary<string, object>
            {
                ["realDevice"] = true
            });
    
            var driver = new IOSDriver(
                new Uri("https://hub.testingbot.com/wd/hub"),
                options
            );
    
            try
            {
                // 1. Open Safari settings via deep link
                driver.ExecuteScript("mobile: deepLink", new Dictionary<string, object>
                {
                    { "url", "app-prefs:com.apple.mobilesafari" }
                });
    
                // 2. Tap "Extensions"
                var extensionsCell = driver.FindElement(MobileBy.IosNsPredicateString(
                    "type == 'XCUIElementTypeCell' AND name == 'Extensions'"));
                extensionsCell.Click();
    
                // 3. Tap extension (e.g., "webrequest-har-collect")
                var extensionItem = driver.FindElement(MobileBy.IosNsPredicateString(
                    "type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'"));
                extensionItem.Click();
    
                // 4. Tap "Allow Extension" switch
                var allowSwitch = driver.FindElement(MobileBy.IosNsPredicateString(
                    "type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'"));
                allowSwitch.Click();
    
                // 5. Tap "All Websites"
                var allWebsites = driver.FindElement(MobileBy.IosNsPredicateString(
                    "type == 'XCUIElementTypeCell' AND name == 'All Websites'"));
                allWebsites.Click();
    
                // 6. Tap "Allow"
                var allow = driver.FindElement(MobileBy.IosNsPredicateString(
                    "type == 'XCUIElementTypeCell' AND name == 'Allow'"));
                allow.Click();
    
                // 7. Terminate Settings app
                driver.ExecuteScript("mobile: terminateApp", new Dictionary<string, object>
                {
                    { "bundleId", "com.apple.Preferences" }
                });
    
                // 8. Launch Safari
                driver.ExecuteScript("mobile: launchApp", new Dictionary<string, object>
                {
                    { "bundleId", "com.apple.mobilesafari" }
                });
    
                // 9. Switch to WebView context
                ReadOnlyCollection<string> contexts = driver.Contexts;
                string webview = contexts.FirstOrDefault(c => c.Contains("WEBVIEW"));
                if (webview != null)
                {
                    driver.Context = webview;
                }
    
                Console.WriteLine("Finished automation steps.");
            }
            finally
            {
                driver.Quit();
            }
        }
    }

Was this page helpful? Yes No 

## Looking for More Help?

Have questions or need more information?   
 You can reach us via the following channels:

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