SauceLabs Selenium: Run WebDriver Tests on 800+ Browser/OS Combinations

SauceLabs Selenium: Run WebDriver Tests on 800+ Browser/OS Combinations

SauceLabs gives you Selenium WebDriver access to 800+ browser/OS combinations without managing infrastructure. You point your RemoteWebDriver at SauceLabs endpoints, pass W3C capabilities to select the browser, and tests run in their cloud. This post covers setup, W3C capabilities, Python and Java examples, parallel execution, Sauce Tunnel for local testing, and CI integration.

How SauceLabs Selenium Works

Your Selenium tests run exactly as they do locally — the only change is the WebDriver endpoint. Instead of launching a local ChromeDriver or geckodriver, you connect to SauceLabs' cloud via RemoteWebDriver. SauceLabs provisions the browser/OS VM, runs your test, records video and screenshots, and tears down.

The connection URL format:

https://SAUCE_USERNAME:SAUCE_ACCESS_KEY@ondemand.us-west-1.saucelabs.com/wd/hub

For EU data center: ondemand.eu-central-1.saucelabs.com

W3C Capabilities

SauceLabs uses W3C WebDriver protocol. The old JSON Wire Protocol desiredCapabilities still works but is deprecated. Use browserName, browserVersion, platformName as standard W3C keys, and put SauceLabs-specific options under sauce:options.

{
  "browserName": "chrome",
  "browserVersion": "latest",
  "platformName": "Windows 11",
  "sauce:options": {
    "name": "My Test Name",
    "build": "Build 42",
    "tags": ["regression", "smoke"],
    "tunnelName": "my-tunnel"
  }
}

Python Setup

Install the Selenium package:

pip install selenium

Basic test connecting to SauceLabs:

import os
from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver

def get_sauce_driver(browser="chrome", version="latest", platform="Windows 11"):
    sauce_options = {
        "name": "SauceLabs Python Test",
        "build": os.environ.get("BUILD_ID", "local"),
        "username": os.environ["SAUCE_USERNAME"],
        "accessKey": os.environ["SAUCE_ACCESS_KEY"],
    }

    options = webdriver.ChromeOptions()
    options.browser_version = version
    options.platform_name = platform
    options.set_capability("sauce:options", sauce_options)

    driver = webdriver.Remote(
        command_executor="https://ondemand.us-west-1.saucelabs.com/wd/hub",
        options=options,
    )
    return driver

def test_homepage():
    driver = get_sauce_driver()
    try:
        driver.get("https://example.com")
        assert "Example" in driver.title
        # Mark test as passed
        driver.execute_script("sauce:job-result=passed")
    except Exception as e:
        driver.execute_script("sauce:job-result=failed")
        raise
    finally:
        driver.quit()

The sauce:job-result JavaScript command is important — it tells SauceLabs whether the test passed or failed so the dashboard reflects the correct status.

Java Setup

Add to pom.xml:

<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.18.1</version>
</dependency>
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.net.URL;

public class SauceLabsTest {
    static final String SAUCE_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub";

    public RemoteWebDriver createDriver() throws Exception {
        ChromeOptions options = new ChromeOptions();
        options.setBrowserVersion("latest");
        options.setPlatformName("Windows 11");

        MutableCapabilities sauceOptions = new MutableCapabilities();
        sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME"));
        sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY"));
        sauceOptions.setCapability("name", "Java SauceLabs Test");
        sauceOptions.setCapability("build", System.getenv("BUILD_ID"));

        options.setCapability("sauce:options", sauceOptions);

        return new RemoteWebDriver(new URL(SAUCE_URL), options);
    }

    public void markTestResult(RemoteWebDriver driver, boolean passed) {
        driver.executeScript("sauce:job-result=" + (passed ? "passed" : "failed"));
    }
}

Browser/OS Matrix

Common combinations for cross-browser coverage:

Browser Version Platform
Chrome latest Windows 11
Chrome latest-1 Windows 10
Firefox latest Windows 11
Safari latest macOS 14
Safari 16 macOS 13
Edge latest Windows 11
IE 11 11 Windows 10

To query available browsers programmatically:

curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
  https://api.us-west-1.saucelabs.com/rest/v1/info/browsers/webdriver

Parallel Execution

Running tests serially on SauceLabs wastes its main advantage. Use pytest-xdist for Python:

pip install pytest-xdist
pytest -n 8 tests/  # Run 8 tests in parallel

Each parallel worker gets its own RemoteWebDriver connection. With a SauceLabs concurrency limit of 10, you can run 10 browser sessions simultaneously.

For pytest, parameterize across browsers:

import pytest

BROWSERS = [
    ("chrome", "latest", "Windows 11"),
    ("firefox", "latest", "Windows 11"),
    ("safari", "latest", "macOS 14"),
]

@pytest.mark.parametrize("browser,version,platform", BROWSERS)
def test_login(browser, version, platform):
    driver = get_sauce_driver(browser, version, platform)
    # ... test code

With -n 3 this runs all three browsers in parallel.

Sauce Connect Tunnel

To test against localhost or staging environments not accessible from the public internet, use Sauce Connect:

# Download Sauce Connect
curl -L https://saucelabs.com/downloads/sauce-connect/5.1.3/sauce-connect-5.1.3_linux.x86_64.tar.gz | tar xz

# Start tunnel
./sc run \
  --username $SAUCE_USERNAME \
  --access-key $SAUCE_ACCESS_KEY \
  --tunnel-name my-tunnel

Then reference the tunnel in capabilities:

sauce_options = {
    "tunnelName": "my-tunnel",
    # ... other options
}

Tests can now reach http://localhost:3000 or internal staging URLs through the tunnel.

CI Integration

GitHub Actions example:

name: Selenium Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Start Sauce Connect
        uses: saucelabs/sauce-connect-action@v2
        with:
          username: ${{ secrets.SAUCE_USERNAME }}
          accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
          tunnelName: github-tunnel-${{ github.run_id }}

      - name: Run Selenium Tests
        env:
          SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
          SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
          BUILD_ID: ${{ github.run_id }}
          TUNNEL_NAME: github-tunnel-${{ github.run_id }}
        run: |
          pip install -r requirements.txt
          pytest tests/ -n 4 --tb=short

Reporting Test Results

SauceLabs captures video, screenshots, and logs for every test. Tag tests with metadata to filter in the dashboard:

sauce_options = {
    "name": f"Login test - {browser}",
    "build": f"PR-{pr_number}",
    "tags": ["login", "smoke", "regression"],
    "customData": {
        "commit": git_sha,
        "branch": branch_name,
    }
}

Access test results via API:

curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
  "https://api.us-west-1.saucelabs.com/rest/v1/$SAUCE_USERNAME/jobs?limit=25&full=true"

Common Issues

Test shows as "complete" but not passed/failed: You're not sending sauce:job-result. Add it to your teardown.

Connection timeout: Check that your network allows outbound connections to ondemand.us-west-1.saucelabs.com:443.

Tunnel not found: The tunnel takes ~30 seconds to establish. Add a health check before running tests:

./sc run --health-check-url http://localhost:3000 &
# await picks up when tunnel is ready

Session limit exceeded: You've hit your concurrency limit. Either reduce -n in pytest-xdist or upgrade your SauceLabs plan.

Read more

Start now free