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/hubFor 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 seleniumBasic 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/webdriverParallel 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 parallelEach 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 codeWith -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-tunnelThen 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=shortReporting 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 readySession limit exceeded: You've hit your concurrency limit. Either reduce -n in pytest-xdist or upgrade your SauceLabs plan.