On this page
Devices you rent from a cloud lab
If you already rent devices on BrowserStack, your workspace can run tests on them. The same NthCase agent that offers the phones on your desk offers them, your access key stays on your machine, and a run on one pays for the thinking and not for the phone.
Every command on this page runs the way Getting the agent describes.
Your lab's devices, as rows in your workspace
Yes, the devices you already rent. Name the BrowserStack devices you want and each one becomes a device a run can lease, exactly like a phone plugged into a machine of yours. The agent that offers them still runs on a machine of yours — it is what holds your key — but that machine needs no phone and no Appium, and nothing is installed on any device by us: the lab installs your build on its own hardware.
One agent can offer both. A phone on your desk and two devices in your lab are three rows from one agent, and neither path weakens the other.
On the runs list, a run on one of these devices says Cloud lab beside the device. The run's own page prints the exact device specification you configured, ready to paste.
Your access key never leaves your machine
NthCase never receives your BrowserStack access key, and cannot. The platform drives the agent by sending it a method, a path, a body and a content type. That is the whole message: there is no header in it and no field that could carry a credential. The agent reads your key on your machine and adds it, on the way out, only to what it sends BrowserStack itself — the session it creates for a run, the device-list check when it starts, and an upload. It never writes the key to disk and never prints it.
Nor does it pass the key back. BrowserStack's answers reach your run through us, so the agent does not count on them leaving your key out: before it passes one on, it replaces the key wherever it appears in it — as written, escaped, percent-encoded, in hex or in base64 — with «redacted».
Set it at a prompt. Your username is not a secret; your key is. Paste this line on its own, because read takes whatever follows it as the value — pasted together with the next line, that line becomes your key:
printf 'BrowserStack access key: ' && read -rs NTH_AGENT_BROWSERSTACK_KEY && echo && export NTH_AGENT_BROWSERSTACK_KEY # paste this line ALONE
export NTH_AGENT_BROWSERSTACK_USER=<your BrowserStack username>
Why a prompt, and not the two obvious alternatives. The key as --browserstack-key is an argument, and every process on the machine can read an argument (ps) for as long as the agent runs. Typing export NTH_AGENT_BROWSERSTACK_KEY=… writes the key verbatim into your shell's history file, which outlives the process, the terminal and the reboot — so "use the variable instead" would be poor advice on its own. The prompt sets the same variable with neither exposure, and says on screen what it is asking for, so it cannot be mistaken for your login password.
First, your build goes into your account
BrowserStack runs its own devices, so a session cannot start until your build is in its storage. There is no adb here and nothing for us to install; this is the lab's rule, not ours. The agent can put the build there: upload needs your BrowserStack username and key and nothing else — no farm and no workspace token — because you need the build's id before connect will start.
npx nthcase-agent upload --file ./app/build/outputs/apk/release/app-release.apk
It prints the build's id and the command to use it with. Hand the id to connect once:
export NTH_AGENT_BROWSERSTACK_APP=bs://<the id it printed>
Two flags, because two different machines fetch the build. Name exactly one; with neither, or both, the agent stops and explains the two.
| Flag | Who fetches the build |
|---|---|
| --file PATH | This agent, from your disk, and it sends the bytes itself. Use it for anything not published on the public internet — which is every pre-release build behind a NAT or a VPN. |
| --url URL | BrowserStack, from its own network: the address is resolved in their data centre, so a build served from your laptop opens in your browser and fails here. Use it only for a build that is genuinely public. |
Four things are checked on your machine before the transfer starts, so a mistake costs a second rather than the whole upload: the path exists, it is a file and not a directory, its extension is one BrowserStack accepts (.apk, .aab, .xapk or .ipa), and it is within their 1 GB limit. The last two are BrowserStack's rules copied into the agent, and if a refusal looks wrong, its message says the refusal may be the agent's rather than your file's.
--custom-id NAME gives the build a name of your own: it works wherever the id does, and uploading again with the same name points it at the new build. BrowserStack deletes an uploaded build after 30 days, and its id stops working then.
If the agent has your credentials and no build, connect stops before it attempts any session. That is deliberate: the lab's own answer to a session with no build is "Platform and Browser not valid.", which sends you to check two things that are fine and never mentions the build.
Which devices: the ones you name
Name each device as its name and its OS version separated by a bar, one flag per device. With your workspace's agent token set the way The token shows, and your key, your username and the build's id from above:
npx nthcase-agent connect --farm https://farm.nthcase.com \ --browserstack-device "Google Pixel 9|15.0" \ --browserstack-device "Samsung Galaxy S23|13.0"
Every flag has a variable twin, and the flag wins when both are set. The variable takes one device, for the common case of one; the flag repeats.
| Flag | Variable |
|---|---|
| --browserstack-user | NTH_AGENT_BROWSERSTACK_USER — your username; not a secret |
| --browserstack-key | NTH_AGENT_BROWSERSTACK_KEY — set it with the prompt above; the flag would put your key in the process list |
| --browserstack-app | NTH_AGENT_BROWSERSTACK_APP — the build's id, or your own name for it |
| --browserstack-device | NTH_AGENT_BROWSERSTACK_DEVICE — one device, as "Name|OsVersion" |
Checked against your own account when the agent starts, at no cost. The agent reads your account's device list — a read that starts no session and spends no device-minute — and every device you named must be on it. A device your account does not offer stops the agent, which names the devices it does offer that are nearest to what you typed. Whether a device is Android or iOS is read from that list, never guessed.
If the list cannot be read at all, the agent offers none of your lab's devices until it is restarted, says why, and keeps running — phones on the same machine are unaffected. Devices named without credentials, or with only half of them, stop the agent with a sentence naming both halves it needs.
You name them; we do not copy your catalogue. An account offers around a hundred devices and you use a handful, and a Devices screen with a hundred rows is a worse product than one with your three. That is a product decision, not a limit: nothing technical stops the agent from offering every one of them.
What a run on one costs
The same as a phone on your desk. The base floor of 2 credits or the AI tokens the run used, whichever is greater — and no device time, however long it runs. NthCase supplied no device, no rack and no electricity: you rent the handset from BrowserStack and pay them for it directly, and charging our physical tier on top would bill you twice for the same hardware.
Nothing can quietly move one of these devices onto that tier: the agent that offers them authenticates as your workspace, so a device in your lab is always your workspace's own. A run that reaches no verdict pays its AI tokens and nothing else, here as everywhere. The full arithmetic is on How a run is priced.
Day two
Routing follows the device, not the flags. Every session goes where its device is — a phone's to the Appium on your machine, a lab device's to BrowserStack — decided from the device the lease named, never from which flags the agent was started with, and every later request for a session goes where that session was created. A session for a phone on your desk is never sent to anybody's lab.
Name the device when it matters which. A run that asks only for a platform or an OS version can be given any available device your workspace can use that matches — one of the farm's, a phone on your desk, or one in your lab — and its price follows the device it got.
The build that runs is the one in your account. On a lab device the lab installs the build the agent names with --browserstack-app, not the build your target names, and one agent names one build for every lab device it offers. The run's own page says so: "The device lab installed its own build, so this run did not use the build this target names — and nothing here can say which one it did use."
A session nobody ends is ended by the agent. If a run stops sending commands — its worker stopped mid-run, say — the lab may retire the session on a timeout of its own. The agent does not rely on that: once a session has been silent for longer than it declared it could be, plus a margin, the agent ends it and says so on its own output, so your BrowserStack account is not billed for a run nobody is watching. If it cannot reach the lab to do that, it says that instead.
Restarting the agent ends what it was driving. It sends every request for a session to where it created that session, and a restarted agent has created none — so a run in flight on one of its devices is refused rather than sent somewhere it does not belong.
An iPhone in the lab needs nothing from your Mac. The lab builds, signs and hosts its own WebDriverAgent; neither your Apple team nor ours reaches it.
No screen mirror and no network capture. A lab device's screen is on the lab's hardware, not on your machine, and the agent shows only phones plugged into the machine it runs on — so a run on a lab device shows no live view, and says so. Network capture is the same: the agent captures only a phone plugged into the machine it runs on, so that run produces no capture either, and its Network tab says capture isn't offered on devices in your own cloud-lab account yet.