What is BrowserStack?
BrowserStack is a cloud-based testing platform that gives engineering teams instant access to more than 3,000 real browsers and devices without requiring any physical hardware investment or maintenance. Founded in 2011 by Ritesh Arora and Nakul Aggarwal, the platform quickly grew to become the go-to cross-browser and cross-device testing solution for companies of all sizes — from individual developers to enterprise engineering organisations at Microsoft, Twitter, General Electric, Nasdaq, and thousands of other teams around the world.
The fundamental problem BrowserStack solves is one every QA and development team knows intimately: your web application or mobile app must work correctly across a staggering variety of browsers, operating systems, and device combinations, but buying and maintaining a physical device lab is prohibitively expensive, time-consuming, and impractical to keep current as new browser versions and devices are released on a constant schedule. Chrome alone releases a new major version every four weeks. iOS releases a new major version every autumn. Android fragmentation means hundreds of active device and OS combinations exist across your user base at any given time.
BrowserStack solves this by maintaining a vast infrastructure of real browsers and real physical devices in its data centres, accessible via the WebDriver protocol (for Selenium and Appium) as well as a live interactive testing interface. You write your test scripts exactly as you would for a local Selenium or Appium setup, point the WebDriver hub URL at BrowserStack's cloud endpoint, and your tests execute against real browsers and devices in real time — complete with video recording, network logs, console logs, and screenshots captured automatically.
BrowserStack Products Overview
BrowserStack has grown beyond simple browser testing into a comprehensive testing platform. The two main products that automation engineers work with daily are Automate (for web and browser testing using Selenium) and App Automate (for native and hybrid mobile app testing using Appium). Beyond these, the platform also offers:
- Percy — Visual regression testing that automatically compares screenshots pixel by pixel and flags unexpected visual changes between builds.
- Test Management — A centralised test case repository, test run tracker, and results dashboard that integrates with Jira and other issue trackers.
- Accessibility Testing — Automated and guided manual accessibility audits against WCAG standards, useful for teams building accessible applications.
- Test Observability — An analytics and intelligence layer built on top of Automate that detects flaky tests, categorises failures, and tracks trends over time.
- Live — An interactive manual testing interface for spot-checking your site on real browsers and devices without any automation.
Why Real Devices and Browsers Matter
A common alternative to BrowserStack is running tests against browser emulators (like the Chrome DevTools mobile simulation mode) or simulators (like iOS Simulator on macOS). While these are useful for development-phase testing, they have well-documented limitations: they do not replicate real device performance characteristics, real network behaviour, real GPU rendering differences, or real browser implementation quirks. A test that passes on a Chrome simulator may still fail on a real Samsung Galaxy S23 due to differences in the WebView version, GPU driver rendering, or touch event handling.
BrowserStack's real devices are actual physical handsets and tablets sitting in air-conditioned data centre racks, each running a real operating system and real browser. When your test taps an element, a real finger-equivalent is touching a real screen. This is the level of fidelity that matters for catching the bugs that actually affect your users.
Pricing Model
BrowserStack pricing is primarily determined by the number of parallel sessions your plan supports. A parallel session is a single simultaneous test execution — one browser or device running at a time. If you need to run 10 browsers simultaneously (parallel testing), you need a plan with 10 parallel sessions. Plans scale from individual developer accounts up to enterprise tiers with unlimited parallel sessions. Teams evaluating BrowserStack can start with a free trial that includes 100 minutes of Automate testing and 100 minutes of App Automate testing with access to the full device and browser catalogue.
Automate vs App Automate
The two primary BrowserStack automation products serve different testing needs. Understanding which product to use for your scenario is the first decision every team must make. Automate is for web applications and browser testing — any scenario where your test navigates a URL in a browser. App Automate is for native Android and iOS apps — any scenario where you install an APK or IPA onto a device and interact with the app's native UI elements.
| Feature | Automate | App Automate |
|---|---|---|
| Purpose | Web and browser testing | Native and hybrid mobile app testing |
| Protocol | Selenium WebDriver | Appium WebDriver |
| Devices | Desktop browsers, mobile browsers | Real Android and iOS physical devices |
| App upload required | No — use a public URL | Yes — upload APK or IPA first |
| Parallel sessions | Up to 25 (plan-dependent) | Up to 25 (plan-dependent) |
| Local testing | BrowserStack Local tunnel | BrowserStack Local tunnel |
| Log types | Network logs, console logs, video | Device logs, app crash logs, video |
| Hub URL | hub.browserstack.com/wd/hub | hub-cloud.browserstack.com/wd/hub |
Both products share the same credential system (username and access key), the same bstack:options capability dictionary structure, and the same dashboard interface. If you are already familiar with one, picking up the other is straightforward — the main differences are the hub URL endpoint, the capabilities you set (device name and OS version for App Automate vs browser name and OS for Automate), and the need to upload your app binary first when working with App Automate.
Account Setup & API Keys
Getting started with BrowserStack takes less than five minutes. Navigate to browserstack.com and create a free account. The free trial provides 100 minutes of Automate testing time and 100 minutes of App Automate time — more than enough to run your first tests and validate your setup before committing to a paid plan.
Finding Your Credentials
Once logged in, your credentials are available at: Account (top-right menu) → Settings → Credentials. You will see your USERNAME (typically in the format firstname_lastname_XXXXX) and your ACCESS_KEY (a long alphanumeric string). Both are required to authenticate with the BrowserStack API and hub endpoint.
Store these as environment variables on your local machine and in your CI/CD system. Never hardcode them in your test scripts or commit them to version control. This is not just a best practice — BrowserStack's security scanner actively monitors public repositories and will rotate exposed keys automatically if it detects them.
# Add to your shell profile (~/.zshrc or ~/.bashrc)
export BROWSERSTACK_USERNAME="your_username"
export BROWSERSTACK_ACCESS_KEY="your_access_key"
# Reload your shell after adding
source ~/.zshrc
In your Python code, read these values from the environment at runtime:
import os
USERNAME = os.environ["BROWSERSTACK_USERNAME"]
ACCESS_KEY = os.environ["BROWSERSTACK_ACCESS_KEY"]
# Fail fast if credentials are missing
if not USERNAME or not ACCESS_KEY:
raise EnvironmentError(
"BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY must be set"
)
This pattern ensures your tests fail immediately with a clear error message if someone runs them without the required environment variables set — rather than failing later with an obscure authentication error from the BrowserStack API.
Selenium on BrowserStack (Python)
Running Selenium tests on BrowserStack requires three changes from a standard local Selenium setup: you replace the local WebDriver initialisation with a webdriver.Remote call pointing at BrowserStack's hub, you add BrowserStack-specific capabilities via the bstack:options dictionary, and you add pass/fail marking via the browserstack_executor JavaScript call. Everything else — your test logic, your locators, your assertions — remains identical to what you would write for local testing.
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
USERNAME = os.environ["BROWSERSTACK_USERNAME"]
ACCESS_KEY = os.environ["BROWSERSTACK_ACCESS_KEY"]
HUB_URL = f"https://{USERNAME}:{ACCESS_KEY}@hub.browserstack.com/wd/hub"
# BrowserStack capabilities
options = webdriver.ChromeOptions()
options.set_capability("bstack:options", {
"os": "Windows",
"osVersion": "11",
"browserVersion": "latest",
"sessionName": "Login Test - Chrome Win11",
"projectName": "QA Chronicles Demo",
"buildName": "Build 1.0",
"video": True,
"networkLogs": True,
"consoleLogs": "info",
})
driver = webdriver.Remote(
command_executor=HUB_URL,
options=options
)
wait = WebDriverWait(driver, 15)
try:
driver.get("https://the-internet.herokuapp.com/login")
wait.until(
EC.visibility_of_element_located((By.ID, "username"))
).send_keys("tomsmith")
driver.find_element(By.ID, "password").send_keys("SuperSecretPassword!")
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
success = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".flash.success"))
)
assert "You logged into a secure area" in success.text
# Mark test as passed in BrowserStack dashboard
driver.execute_script(
'browserstack_executor: {"action": "setSessionStatus",'
'"arguments": {"status": "passed", "reason": "Login successful"}}'
)
except Exception as e:
driver.execute_script(
f'browserstack_executor: {{"action": "setSessionStatus",'
f'"arguments": {{"status": "failed", "reason": "{str(e)}"}}}}'
)
raise
finally:
driver.quit()
Understanding bstack:options
The bstack:options capability dictionary is BrowserStack's structured way of passing platform configuration. The key fields you will set on virtually every test session are:
- os / osVersion — The operating system. Options include "Windows" (10, 11), "OS X" (Monterey, Ventura, Sonoma), and more.
- browserVersion — "latest" always gives you the current stable release, or pin to a specific version like "120".
- sessionName — A human-readable label shown in the BrowserStack dashboard for this test run. Make it descriptive.
- projectName / buildName — Grouping identifiers. projectName is your application or project, buildName is the CI build or release version. These make your results searchable and comparable over time.
- video: True — Records a full video of the test execution. Essential for debugging failures.
- networkLogs: True — Captures network HAR file. Useful for diagnosing API call failures during UI tests.
- consoleLogs: "info" — Captures browser console output at the specified level (errors, warnings, info, verbose).
Selenium on BrowserStack (Java)
The Java equivalent follows the same pattern — read credentials from environment variables, configure capabilities via a HashMap passed as bstack:options, create a RemoteWebDriver instance, run your test, and mark the session as passed or failed. This example uses plain Selenium WebDriver and is compatible with both JUnit and TestNG test frameworks.
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.net.URL;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
public class BrowserStackTest {
public static void main(String[] args) throws Exception {
String username = System.getenv("BROWSERSTACK_USERNAME");
String accessKey = System.getenv("BROWSERSTACK_ACCESS_KEY");
String hubUrl = "https://" + username + ":" + accessKey
+ "@hub.browserstack.com/wd/hub";
ChromeOptions options = new ChromeOptions();
HashMap<String, Object> bstackOptions = new HashMap<>();
bstackOptions.put("os", "Windows");
bstackOptions.put("osVersion", "11");
bstackOptions.put("browserVersion", "latest");
bstackOptions.put("sessionName", "Login Test - Java");
bstackOptions.put("projectName", "QA Chronicles Demo");
bstackOptions.put("buildName", "Build 1.0");
bstackOptions.put("video", true);
bstackOptions.put("networkLogs", true);
options.setCapability("bstack:options", bstackOptions);
RemoteWebDriver driver = new RemoteWebDriver(new URL(hubUrl), options);
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
try {
driver.get("https://the-internet.herokuapp.com/login");
wait.until(ExpectedConditions
.visibilityOfElementLocated(By.id("username")))
.sendKeys("tomsmith");
driver.findElement(By.id("password"))
.sendKeys("SuperSecretPassword!");
driver.findElement(By.cssSelector("button[type='submit']")).click();
wait.until(ExpectedConditions
.presenceOfElementLocated(By.cssSelector(".flash.success")));
driver.executeScript(
"browserstack_executor: {\"action\": \"setSessionStatus\","
+ "\"arguments\": {\"status\": \"passed\","
+ "\"reason\": \"Login test passed\"}}"
);
} catch (Exception e) {
driver.executeScript(
"browserstack_executor: {\"action\": \"setSessionStatus\","
+ "\"arguments\": {\"status\": \"failed\","
+ "\"reason\": \"" + e.getMessage() + "\"}}"
);
throw e;
} finally {
driver.quit();
}
}
}
For teams using Maven, add the Selenium dependency to your pom.xml:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.21.0</version>
</dependency>
App Automate — Mobile on Real Devices
App Automate extends BrowserStack's cloud infrastructure to native Android and iOS application testing. Instead of navigating a URL in a browser, your test installs your APK or IPA binary onto a real physical device in BrowserStack's data centre and interacts with the native app using the Appium WebDriver protocol.
The workflow for App Automate has one additional step compared to Automate: you must upload your app binary to BrowserStack before running tests. BrowserStack stores the uploaded binary and gives you a unique bs:// URL that your test capabilities reference. This app URL remains valid for 30 days, so you only need to re-upload when your app binary changes — which is typically on each CI build that produces a new APK or IPA.
The App Automate Workflow
The complete workflow from build to test execution on BrowserStack App Automate is:
- Your CI pipeline builds the application — either an Android APK or iOS IPA file.
- Your test pipeline uploads the binary to BrowserStack via the App Automate REST API, receiving a
bs://app URL in response. - Your Appium test script is configured with that app URL and the target device name plus OS version.
- BrowserStack installs the app on the specified real device, starts an Appium session, and executes your test.
- Results — including a full session video, device logs, Appium logs, and screenshots — are available in the BrowserStack dashboard.
This workflow integrates naturally into CI/CD pipelines where each successful build triggers an automated regression run on real devices, giving your team rapid feedback on whether the new build works correctly on the devices your users actually own.
App Automate with Python
The Python implementation for App Automate uses the Appium Python client rather than the Selenium client, and targets BrowserStack's separate App Automate hub endpoint. Note that the hub URL is different from Automate: it uses hub-cloud.browserstack.com rather than hub.browserstack.com.
import os
import requests
from appium import webdriver
from appium.options import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
USERNAME = os.environ["BROWSERSTACK_USERNAME"]
ACCESS_KEY = os.environ["BROWSERSTACK_ACCESS_KEY"]
# Step 1: Upload your APK to BrowserStack App Automate
def upload_app(apk_path: str) -> str:
"""Upload an APK to BrowserStack and return the bs:// app URL."""
url = "https://api-cloud.browserstack.com/app-automate/upload"
with open(apk_path, "rb") as f:
response = requests.post(
url,
files={"file": f},
auth=(USERNAME, ACCESS_KEY)
)
response.raise_for_status()
app_url = response.json()["app_url"]
print(f"App uploaded successfully: {app_url}")
return app_url # Returns "bs://abc123..."
# Step 2: Configure capabilities and run test
# Replace with the app_url returned from upload_app()
APP_URL = "bs://your-uploaded-app-url-here"
options = UiAutomator2Options()
options.platform_name = "Android"
options.set_capability("app", APP_URL)
options.set_capability("bstack:options", {
"deviceName": "Samsung Galaxy S23",
"osVersion": "13.0",
"sessionName": "Android App Smoke Test",
"projectName": "Mobile App Tests",
"buildName": "Release 2.0",
"video": True,
"deviceLogs": True,
"appiumVersion": "2.6.0",
})
hub_url = f"https://{USERNAME}:{ACCESS_KEY}@hub-cloud.browserstack.com/wd/hub"
driver = webdriver.Remote(hub_url, options=options)
wait = WebDriverWait(driver, 20)
try:
# Wait for the app to launch and interact with the native UI
wait.until(
EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "open menu"))
).click()
wait.until(
EC.visibility_of_element_located((AppiumBy.ACCESSIBILITY_ID, "Settings"))
).click()
# Mark session as passed
driver.execute_script(
'browserstack_executor: {"action": "setSessionStatus",'
'"arguments": {"status": "passed", "reason": "App smoke test passed"}}'
)
except Exception as e:
driver.execute_script(
f'browserstack_executor: {{"action": "setSessionStatus",'
f'"arguments": {{"status": "failed", "reason": "{str(e)}"}}}}'
)
raise
finally:
driver.quit()
Choosing Devices for App Automate
BrowserStack provides hundreds of real Android and iOS devices. Rather than testing on every available device, use your application's analytics data to identify the top devices and OS versions actually used by your audience. A common starting configuration is to test on:
- The latest iPhone (Safari/WebKit, representative of iOS current users)
- A mid-range Samsung Galaxy (representative of the Android mid-market majority)
- A Samsung Galaxy on the previous Android major version (to catch OS-level regressions)
This three-device configuration gives you broad coverage of your real user base without excessive test execution time or session cost. Expand to more devices when your analytics show significant traffic from additional device/OS combinations.
Parallel Testing
One of BrowserStack's most powerful capabilities is the ability to run tests in parallel across multiple browser and device configurations simultaneously. Rather than running your test suite sequentially on Chrome, then Firefox, then Safari — which triples your test execution time — parallel testing runs all three simultaneously, completing in roughly the same time as running on a single browser.
With pytest and pytest-xdist, parallel BrowserStack testing is straightforward. Define your target browser configurations as a parametrize fixture and let pytest-xdist distribute them across parallel workers:
# conftest.py
import pytest
import os
from selenium import webdriver
USERNAME = os.environ["BROWSERSTACK_USERNAME"]
ACCESS_KEY = os.environ["BROWSERSTACK_ACCESS_KEY"]
HUB_URL = f"https://{USERNAME}:{ACCESS_KEY}@hub.browserstack.com/wd/hub"
BROWSERS = [
{
"os": "Windows", "osVersion": "11",
"browser": "Chrome", "browserVersion": "latest"
},
{
"os": "Windows", "osVersion": "11",
"browser": "Firefox", "browserVersion": "latest"
},
{
"os": "OS X", "osVersion": "Ventura",
"browser": "Safari", "browserVersion": "16"
},
]
@pytest.fixture(params=BROWSERS, ids=["chrome", "firefox", "safari"])
def driver(request):
config = request.param
if config["browser"] == "Firefox":
options = webdriver.FirefoxOptions()
elif config["browser"] == "Safari":
options = webdriver.SafariOptions()
else:
options = webdriver.ChromeOptions()
options.set_capability("bstack:options", {
**config,
"sessionName": f"Parallel Test - {config['browser']} {config['osVersion']}",
"projectName": "QA Chronicles Demo",
"buildName": "Parallel Build",
"video": True,
})
driver = webdriver.Remote(command_executor=HUB_URL, options=options)
yield driver
driver.quit()
# tests/test_parallel.py
def test_homepage_loads(driver):
driver.get("https://the-internet.herokuapp.com/")
assert "The Internet" in driver.title
def test_login_flow(driver):
driver.get("https://the-internet.herokuapp.com/login")
# ... test logic
Run the full suite in parallel across all three browser configurations simultaneously:
# Run with 3 parallel workers — one per browser configuration
pytest tests/ -n 3 --html=report.html --self-contained-html
This command distributes the parametrized test cases across three parallel pytest workers, each of which creates a separate BrowserStack session for its assigned browser. Your test suite that might take 15 minutes to run sequentially across three browsers completes in approximately 5 minutes — the time of a single browser run.
BrowserStack Local
BrowserStack Local is a secure tunnel that connects your BrowserStack session to resources on your private network — your local development server, a staging environment behind a corporate VPN, or any server that is not publicly accessible on the internet. Without BrowserStack Local, your BrowserStack session can only reach publicly accessible URLs. With it, a browser running in BrowserStack's data centre can access localhost:3000 on your laptop or staging.internal.company.com behind your firewall.
# Download BrowserStack Local binary from:
# https://www.browserstack.com/local-testing/automate
# On Linux/macOS — make executable and start the tunnel
chmod +x BrowserStackLocal
./BrowserStackLocal --key $BROWSERSTACK_ACCESS_KEY \
--local-identifier "my-unique-tunnel-id" &
# Wait a moment for the tunnel to establish, then run your tests
echo "Tunnel started. Running tests..."
pytest tests/local/ -n 2
In your test capabilities, tell BrowserStack to route the session through your local tunnel:
options.set_capability("bstack:options", {
"os": "Windows",
"osVersion": "11",
"browserVersion": "latest",
"sessionName": "Staging Test - Chrome",
"local": True, # Enable BrowserStack Local
"localIdentifier": "my-unique-tunnel-id", # Match the tunnel ID above
})
BrowserStack Local Use Cases
The most common scenarios where BrowserStack Local is essential include:
- Testing a development server — Your feature branch is running on
localhost:8080and you want to verify it looks correct on real iOS Safari before pushing. - Staging environment testing — Your staging environment is behind a VPN or firewall. BrowserStack Local runs on a machine inside the network, giving BrowserStack's cloud sessions access to the staging URL.
- Pre-production validation — Running your full cross-browser suite against a staging build before the production deployment window.
- CI pipeline testing of feature branches — Your CI runner starts BrowserStack Local, runs the test suite against the locally deployed branch, then stops the tunnel.
GitHub Actions Integration
Integrating BrowserStack with GitHub Actions makes cross-browser testing an automatic part of every pull request and main branch merge. Tests run in the cloud without requiring any infrastructure changes to your CI runner — the runner simply needs network access to BrowserStack's endpoints, which is available from any GitHub Actions runner.
name: BrowserStack Cross-Browser Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
browserstack:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run BrowserStack Tests
env:
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
BUILD_NAME: "GH Actions - ${{ github.run_number }}"
run: |
pytest tests/browserstack/ \
-n 3 \
--html=report.html \
--self-contained-html \
-v
- name: Upload Test Report
uses: actions/upload-artifact@v4
if: always()
with:
name: browserstack-report-${{ github.run_number }}
path: report.html
retention-days: 14
Store your BrowserStack credentials as GitHub Secrets: navigate to your repository Settings → Secrets and variables → Actions → New repository secret. Add BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY. These values are injected into the workflow environment at runtime and never appear in logs. Never commit credentials in your workflow YAML, .env files, or anywhere in your repository.
Passing Build Information to BrowserStack
A useful pattern for CI integration is passing GitHub Actions context variables to BrowserStack's buildName capability so that each CI run creates a distinctly identifiable build in the BrowserStack dashboard. Set the build name in your GitHub Actions environment and read it in your test code:
# In GitHub Actions workflow:
# BUILD_NAME: "GH Actions - ${{ github.run_number }}"
# In your test conftest.py:
import os
BUILD_NAME = os.getenv("BUILD_NAME", "Local Dev Build")
Test Observability Dashboard
BrowserStack Test Observability is an analytics intelligence layer built directly into the Automate dashboard. It goes beyond storing test results to actively analysing your test suite's health and helping you identify patterns that indicate systemic problems. Enabling it is a single capability addition to your existing test configuration.
Enabling Test Observability
options.set_capability("bstack:options", {
"os": "Windows",
"osVersion": "11",
"browserVersion": "latest",
"sessionName": "Regression Suite",
"projectName": "QA Chronicles Demo",
"buildName": "Build 1.0",
"video": True,
"testObservability": True, # Enable Test Observability
})
What Test Observability Provides
Once enabled, Test Observability analyses your test runs across builds and surfaces the following insights:
- Flaky test detection — Tests that sometimes pass and sometimes fail without code changes are automatically flagged. Flaky tests erode team confidence in the test suite and cause false alarms in CI. Identifying them is the first step to fixing them.
- Failure categorisation — Test Observability attempts to categorise each failure as a "product bug" (the application broke) or an "automation bug" (the test script broke due to a selector change, timing issue, etc.). This saves triage time by routing failures to the right team immediately.
- Historical trend analysis — Charts showing pass rate, failure rate, and flakiness over time across builds. A rising error rate over three days is a much more actionable signal than a single failed build.
- Error grouping — Identical or similar error messages across multiple test runs are automatically grouped, helping you see that 15 tests are failing for the same root cause rather than treating each as a separate issue.
Review the Test Observability dashboard at automate.browserstack.com/builds — it updates in real time as tests execute and provides a historical view of all past builds for your project.
setSessionStatus executor script, all sessions show as 'unknown' in the dashboard, which makes the build history useless for trend analysis. Always add pass/fail marking to your finally block."
Best Practices
After working with BrowserStack across multiple projects — from web portal testing at Viasat to mobile app validation — these are the practices that consistently lead to reliable, maintainable BrowserStack test suites.
- Always set sessionName, projectName, and buildName. Without these, your BrowserStack dashboard becomes a sea of unnamed sessions that are impossible to search, compare, or debug. Good names look like:
sessionName="Login Flow - Chrome Win11",projectName="Inflight Portal",buildName="Release 4.2.1 - Build 87". - Always mark tests as passed or failed via the executor script. BrowserStack cannot infer pass/fail from your test framework. Without explicit marking, every session shows as "unknown" in the dashboard, destroying the value of historical trend data. Add the executor call in both the success path and the except block.
- Enable video recording for all tests initially. During the first few weeks of running tests on BrowserStack, video recording for every session is invaluable for debugging unexpected failures. Once your suite is stable, you can selectively disable video for your fastest smoke tests to save recording storage.
- Store credentials as environment variables or CI secrets. Never hardcode
BROWSERSTACK_USERNAMEorBROWSERSTACK_ACCESS_KEYin code, never commit.envfiles containing them to git. BrowserStack's security scanner actively scans public repositories and rotates exposed keys — but by then the damage is done. - Use BrowserStack Local only when genuinely needed. The Local tunnel adds setup overhead and a potential failure point to your pipeline. If your test target is publicly accessible, test it directly without the tunnel — it's faster and simpler.
- Run a smoke suite on every commit, full regression less frequently. Your complete cross-browser regression suite with 5+ browser configurations might take 20–30 minutes even in parallel. Run a 5-minute smoke suite on every PR and commit. Reserve the full cross-browser regression for nightly runs or pre-release gates.
- Test on at least three browser and OS combinations for web testing. A minimum meaningful cross-browser configuration is Chrome on Windows (highest global market share), Safari on macOS (critical for Apple ecosystem users), and Firefox on Windows (important in privacy-conscious markets and enterprise). Add mobile browsers based on your analytics.
- For mobile, test on the top three devices from your analytics. Look at your real user data — Google Analytics or Firebase Analytics — and identify the three device models and OS versions sending the most traffic. Test on those first. Expand as time and session budgets allow.
- Use network throttling for mobile browser tests. BrowserStack supports network condition emulation via the
networkProfilecapability. Setting it to "3G" for a mobile browser test session simulates realistic mobile network conditions and can expose performance issues that are invisible on fast office Wi-Fi. - Review the Test Observability dashboard weekly. Flaky tests do not fix themselves. Set a recurring weekly calendar reminder to check the Observability dashboard for newly detected flaky tests and rising error rates. Early intervention prevents flakiness from spreading through the suite and eroding team confidence.
Architecture Overview
The following diagram shows the end-to-end flow from your test script to BrowserStack's infrastructure:
Your test script connects to the BrowserStack hub endpoint using your credentials. The hub routes the session to an available browser or device instance in BrowserStack's cloud. Commands from your script are executed on the real browser or device, and responses (element states, screenshots, logs) travel back through the same channel to your test script. The entire interaction is recorded and stored in the BrowserStack dashboard for review.
Summary
BrowserStack is a mature, reliable platform that solves the real-world problem of maintaining cross-browser and cross-device test coverage without the overhead of managing physical hardware. Its integration with Selenium and Appium means you can adopt it without rewriting your existing test scripts — simply redirect your WebDriver connections to the BrowserStack hub, add capabilities, and mark your test outcomes. Combined with GitHub Actions for automated execution, Test Observability for trend monitoring, and BrowserStack Local for staging environment access, it provides a comprehensive foundation for professional-grade cross-platform test automation.