---
title: "BrowserStack"
description: "Run agent-qa tests on BrowserStack: web tests over Playwright, Android and iOS device tests over Appium, app uploads, BrowserStack Local tunnels and session marks."
canonical_url: "https://vostride.com/docs/agent-qa/plugins/browserstack"
md_url: "https://vostride.com/docs/agent-qa/plugins/browserstack.md"
last_updated: "2026-11-07T15:25:39+05:30"
---

> [Documentation index](https://vostride.com/docs.md) · [Site index](https://vostride.com/llms.txt)
> Follow the Markdown links to read individual pages; the indexes list the available documentation.

# BrowserStack

> Run agent-qa tests on BrowserStack: web tests over Playwright, Android and iOS device tests over Appium, app uploads, BrowserStack Local tunnels and session marks.

The BrowserStack plugin, `@vostride/agent-qa-plugin-browserstack`, runs web tests on [BrowserStack](https://www.browserstack.com) browsers over the Playwright protocol, and mobile tests on BrowserStack Android and iOS devices over Appium. It uploads your app once per build, links each test to its BrowserStack session, and marks the session passed or failed.

BrowserStack runs only the Playwright versions it lists, and the plugin keeps a copy of that list: 1.59 to 1.63 in agent-qa 0.3.2. agent-qa 0.3.2 runs Playwright 1.64, so web tests on BrowserStack are refused with kind `version` until a plugin release adds it. Device tests are not affected. `agent-qa doctor` warns while this is the case.

## Install
Install the plugin at exactly the version of agent-qa your project runs:

```bash
npm install --save-dev --save-exact @vostride/agent-qa-plugin-browserstack@$(npx agent-qa --version)
```

## Configure
One `plugins` entry holds the account. Add a remote for each place you run, and point devices at a device remote:

```yaml
plugins:
  - name: browserstack
    package: "@vostride/agent-qa-plugin-browserstack"
    options:
      username: "{{secret:BROWSERSTACK_USERNAME}}"
      accessKey: "{{secret:BROWSERSTACK_ACCESS_KEY}}"

registry:
  remotes:
    - name: browserstack
      plugin: browserstack
      settings:
        os: Windows
        osVersion: "11"
    - name: browserstack-devices
      plugin: browserstack
  devices:
    bs-pixel:
      platform: android
      remote: browserstack-devices
      model: Google Pixel 9
      os: "15"
```

A web test runs on BrowserStack with `use.browser.remote: browserstack` in the config, a suite or the test. A mobile test runs there when its device, here `bs-pixel`, names a BrowserStack remote. Put both credentials in your secrets file.

## Options
Options belong to the `plugins` entry and describe the account.

| Option | Default | Meaning |
| --- | --- | --- |
| `username` | required | The BrowserStack username, a credential. |
| `accessKey` | required | The BrowserStack access key, a credential. |
| `local` | `false` | Start a [BrowserStack Local](https://vostride.com/docs/agent-qa/plugins/browserstack.md#browserstack-local) tunnel for the run. |
| `localIdentifier` | | The tunnel's identifier. Without `local`, a tunnel you already run. |
| `localBinary` | | The BrowserStackLocal binary to run, instead of the one the wrapper finds or downloads. Needs `local: true`. |
| `apiUrl` | `https://api.browserstack.com` | The Automate API: web session lookups, marks and the plan. |
| `appApiUrl` | `https://api-cloud.browserstack.com` | The App Automate API: uploads, device sessions and the plan. |
| `hubUrl` | `https://hub.browserstack.com/wd/hub` | The Appium hub device sessions connect to. |
| `playwrightUrl` | `wss://cdp.browserstack.com/playwright` | The Playwright endpoint web sessions connect to. |

Write both credentials as `{{secret:NAME}}` references. Leave the four endpoints unset unless BrowserStack tells you otherwise; they must use `https://`, or `wss://` for `playwrightUrl`, with no user or password, unless they point at this machine.

The credentials travel only in the Playwright URL, in the device capabilities and in the basic auth header of BrowserStack's REST API, and agent-qa masks them everywhere they could be printed or recorded.

## Settings
Settings belong to each remote and describe one place.

| Setting | Default | Meaning |
| --- | --- | --- |
| `os` | `OS X` | The web session's operating system, such as `Windows`. |
| `osVersion` | `Sequoia` | The operating system version, such as `11` or `Sequoia`. |
| `browser` | by engine | `chrome`, `edge`, `playwright-chromium`, `playwright-firefox` or `playwright-webkit`. |
| `browserVersion` | | The Chrome or Edge version, such as `latest` or `latest-1`. |
| `project` | `agent-qa` | The BrowserStack project sessions are filed under. |
| `build` | the run ID | The BrowserStack build name. |
| `appiumVersion` | `3.5.2` | The Appium version device sessions ask for. |
| `extra` | | Capabilities merged last, overriding the ones above. |

## Web tests
A web session asks BrowserStack for:

- `browser`: the `browser` setting, or the one that matches the test's engine: `chrome` for Chromium, `playwright-firefox` for Firefox and `playwright-webkit` for WebKit. A browser that cannot run the test's engine is refused at `settings.browser`;
- `os`, `os_version` and, when set, `browser_version`;
- the Playwright version agent-qa runs, which BrowserStack must list;
- `project`, `build` and `name`, the test's name, so each run is one build in BrowserStack's dashboard;
- `extra`, merged last.

To run the same tests on several browsers, add a remote for each and pick one per suite:

```yaml
registry:
  remotes:
    - name: bs-windows-edge
      plugin: browserstack
      settings: { os: Windows, osVersion: "11", browser: edge }
    - name: bs-mac-webkit
      plugin: browserstack
      settings: { os: OS X, osVersion: Sequoia, browser: playwright-webkit }
```

The suite's engine must fit the browser: `edge` and `chrome` run Chromium tests, so a suite on `bs-mac-webkit` also sets `use.browser.name: webkit`.

## Device tests
A device session connects to BrowserStack's Appium hub. agent-qa sends the device's identity, `model` as `appium:deviceName` and `os` as `appium:platformVersion`, and BrowserStack picks a real device that matches. The plugin adds `bstack:options` with:

- the credentials;
- `appiumVersion`: the device's own `bstack:options.appiumVersion` capability, else the `appiumVersion` setting, else `3.5.2`;
- `projectName`, `buildName` and `sessionName`, the test's name;
- `extra`, merged last.

The device's own `capabilities` are merged over all of that.

```yaml
registry:
  devices:
    bs-iphone:
      platform: ios
      remote: browserstack-devices
      model: iPhone 16
      os: "18"
  targets:
    shop-ios:
      platform: ios
      bundleId: com.example.shop
      device: bs-iphone
      app:
        path: builds/Shop.ipa
```

## Apps
A device test needs the app on BrowserStack:

- **`app.ref` wins.** When the target sets `app.ref`, a `bs://` ID from an earlier upload or an `https` URL, BrowserStack installs that app and nothing is uploaded.
- **Otherwise the plugin uploads `app.path`.** It names the file by its content, `agent-qa-` and the first 32 hex digits of its SHA-256, and reuses the newest upload under that name. Only a build it has not seen is uploaded, with progress in the run, such as `uploading app (84 MB)`. BrowserStack keeps an upload for 30 days.

An upload may take up to the remote's `uploadTimeout`, ten minutes by default. The plugin checks that the file still has the size and hash agent-qa saw before it sends it.

## BrowserStack Local
BrowserStack Local is a tunnel that lets BrowserStack's browsers and devices reach a target only your machine can reach, such as `localhost` or a staging host behind a VPN. Turn it on in the entry:

```yaml
plugins:
  - name: browserstack
    package: "@vostride/agent-qa-plugin-browserstack"
    options:
      username: "{{secret:BROWSERSTACK_USERNAME}}"
      accessKey: "{{secret:BROWSERSTACK_ACCESS_KEY}}"
      local: true
```

- `local: true` starts one tunnel on the run's first session, with a fresh identifier or `localIdentifier` when set, and every web and device session of the run uses it. The plugin stops the tunnel when the run ends, and when agent-qa is stopped.
- `localIdentifier` without `local` uses a tunnel you already run under that identifier. The plugin starts nothing.
- The tunnel comes from BrowserStack's `browserstack-local` package, which finds BrowserStack's binary in `~/.browserstack`, the working folder or the temp folder, and downloads it when none is there. `localBinary` names a binary to run instead.
- The tunnel logs to a fresh file in the temp folder, readable only by you. Nothing is written into the project.
- Before it starts the tunnel, the plugin checks that this machine can run the binary. A binary it cannot run refuses the session with kind `unreachable` at `options.local`, or `options.localBinary` when that is set, and the line says how to fix it:

| Cause | Fix |
| --- | --- |
| `EBADARCH`: a Mac binary built for another CPU | Install Rosetta with `softwareupdate --install-rosetta --agree-to-license`, or set `localBinary` to a binary built for this Mac. The wrapper downloads BrowserStack's Intel build on every Mac. |
| `ENOENT`: the path does not exist | Set `localBinary` to the path of a BrowserStackLocal binary. |
| `EACCES`: the file is not executable | Make it executable, or set `localBinary` to one that is. |
| Anything else | Set `localBinary` to a binary this machine can run. |

If the tunnel starts but then fails, the session is refused the same way, and the line names the tunnel's log.

BrowserStack's tunnel binary takes the access key as `--key` on its command line. That is BrowserStack's design, and it means other users of the same machine can read the key with `ps` while the tunnel runs.

## Links and marks
When a session starts, the test gets a link to its page in BrowserStack's dashboard, which needs a BrowserStack login. agent-qa prints it as `Remote <name>: <link>` and the run page shows it. BrowserStack's shareable public URL is never used.

When the test ends, the plugin marks the session:

| Outcome | Mark |
| --- | --- |
| Passed | `passed` |
| Failed | `failed`, with the reason, cut to 255 characters |
| agent-qa's own error | `failed`, with agent-qa's sentence |
| Cancelled | none |

A device session is found by its WebDriver session ID. A web session is found through BrowserStack's API: the one running session in the run's build with the test's name, started after agent-qa asked for it. When none or several match, the test gets no link and the session stays unmarked; a guessed session is never marked. A lookup or mark that fails never fails the test.

## Account check
`agent-qa doctor` runs the plugin's account check, which opens no session:

- it reads the Automate and App Automate plans, and reports each product's sessions, such as `Automate: 1 of 5 parallel sessions running, 0 queued`;
- it warns `the username or access key was refused` when BrowserStack refuses them, and that a product is not on the account, such as `App Automate is not on this account`;
- it warns when BrowserStack does not list agent-qa's Playwright version.

## When a remote is refused
| Kind | Cause | Fix |
| --- | --- | --- |
| `auth` | BrowserStack responded with 401. | Check the username and access key in your secrets file. |
| `capacity` | BrowserStack responded with 429: every parallel session is in use, or the API rate limit was hit. | Wait, or lower `use.workers`. |
| `version` | BrowserStack does not list agent-qa's Playwright version. | Run web tests here or on another remote until a plugin release adds it. |
| `refused` at a path such as `settings.browser` | That setting or option is wrong. | Fix the line it names. |
| `refused` with no path | BrowserStack responded with another error. | Read the status and message in the line. |
| `unreachable` | BrowserStack did not respond. | Check the network. |
| `unreachable` at `options.local` or `options.localBinary` | The tunnel did not start. | Follow the fix in the line, or read the tunnel's log it names. |

`npx agent-qa plugins describe browserstack --json` lists every option and setting with its type, default and description.

## Documentation navigation

- [All documentation](https://vostride.com/docs.md)
- Parent: [Plugins](https://vostride.com/docs/agent-qa/plugins.md)
- Previous: [Plugins](https://vostride.com/docs/agent-qa/plugins.md)
- Next: [Hyperbrowser](https://vostride.com/docs/agent-qa/plugins/hyperbrowser.md)
