How VU Hours (VUH) are calculated
Understand how BrowserStack Load Testing estimates, consumes, and tracks VU Hours across adjusted virtual users, multi-engine, multi-region, hybrid, and iteration-based tests.
VU Hours (VUH) measure the compute you consume when you run load tests on BrowserStack. Your plan includes a monthly VUH quota, tracked separately for API tests (k6, JMeter, Gatling, Locust) and browser tests (Playwright, Selenium, WebdriverIO, Nightwatch). This page explains how VUH is calculated so your usage dashboard holds no surprises.
Adjusted Virtual Users
BrowserStack bills based on Adjusted Virtual Users the compute capacity reserved for your test, not just the VU count you configure.
Each API load test engine reserves a fixed capacity of 1,000 VUs, regardless of how many VUs you actually configure. An engine running 500 VUs reserves the same compute as one running 1,000 VUs — the same memory and CPU allocation. So VUH is calculated from the reserved capacity, not the configured VUs.
The formula to calculate
For API tests:
Engines = ceil(Your VUs / 1,000)
Adjusted VUs = Engines × 1,000
VU-seconds = Adjusted VUs × Duration (in seconds)
VU Hours = VU-seconds ÷ 3,600
BrowserStack stores consumption internally in VU-seconds and converts to VU Hours (÷ 3,600) for display on your usage dashboard.
Examples
The following examples show how engines, Adjusted VUs, and VUH scale with your configured VUs:
| Your VUs | Engines | Adjusted VUs | Duration | VUH |
|---|---|---|---|---|
| 500 | 1 | 1,000 | 10 min (600s) | 1,000 × 600 ÷ 3,600 = 166.67 |
| 1,000 | 1 | 1,000 | 10 min | 166.67 |
| 1,500 | 2 | 2,000 | 10 min | 333.33 |
| 2,500 | 3 | 3,000 | 10 min | 500.00 |
500 VUs and 1,000 VUs cost the same VUH as both use only one engine. The jump happens at 1,001 VUs, when a second engine is allocated.
Browser tests are not adjusted
Browser tests (Playwright, Selenium, WebdriverIO, Nightwatch) run 1 VU per pod, so Adjusted VUs equal your configured VUs. There is no rounding up.
VUH by load profile
How VUH is estimated depends on the load profile you choose:
| Load profile | How VUH is estimated | Example (500 VUs, JMeter) |
|---|---|---|
| Constant | Adjusted VUs × Duration | 1,000 × 600s ÷ 3,600 = 166.67 VUH |
| Ramping | Adjusted VUs × Duration (peak VUs) | 1,000 × 600s ÷ 3,600 = 166.67 VUH |
| Spike | Adjusted VUs × Duration (peak VUs) | 1,000 × 600s ÷ 3,600 = 166.67 VUH |
| Iterations | Adjusted VUs × your plan’s max duration | 1,000 × 1,200s ÷ 3,600 = 333.33 VUH |
For ramping and spike profiles, the pre-run estimate uses peak VUs as a conservative upper bound. The actual VUH consumed reflects the real VU curve, which is usually lower during ramp-up and ramp-down phases.
Iteration-based tests don’t have a fixed duration, so VUH is estimated using your plan’s maximum test duration. The actual VUH consumed is lower when iterations complete before that limit.
Multi-region tests
When you split a test across regions, each region runs on at least one engine. BrowserStack allocates engines per region using the following rule:
Engines per region = max(1, floor(region percent × total engines / 100))
Because of this per-region floor, a multi-region test can use more engines, and therefore more VUH than the same test run from a single region.
Consider 1,000 VUs split 60/40 across two regions, running for 10 minutes. The auto engine count is ceil(1,000 / 1,000) = 1, but each region still gets at least one engine:
| Region | Engine calculation | Engines |
|---|---|---|
| Region A (60%) | max(1, floor(0.6 × 1)) | 1 |
| Region B (40%) | max(1, floor(0.4 × 1)) | 1 |
| Total | Â | 2 |
Adjusted VUs = 2 engines × 1,000 = 2,000
VU Hours = 2,000 × 600s ÷ 3,600 = 333.33 VUH
Splitting a test across regions can increase the total engine count, and therefore the VUH, compared to running the same test from a single region. The region split affects where load originates and how many engines are reserved; plan for the higher engine count when you distribute load.
Multi-engine tests (JMeter)
For JMeter tests, you can set an explicit engine count instead of letting BrowserStack auto-calculate it. When set, VUH uses that engine count directly. The maximum is 10 engines.
Set the engine count in the Advanced Settings tab in the dashboard, or as engineCount: <number> in your YAML configuration. The following examples show how an explicit engine count changes VUH:
| Your VUs | Engine count | Adjusted VUs | Duration | VUH |
|---|---|---|---|---|
| 500 | Auto (1) | 1,000 | 10 min | 166.67 |
| 500 | 3 (explicit) | 3,000 | 10 min | 500.00 |
| 1,000 | 3 (explicit) | 3,000 | 10 min | 500.00 |
Set an engine count only when you need reproducible distributed execution. Auto mode uses the fewest engines needed, which minimizes VUH.
Multi-scenario tests
The multiple scenarios feature models several user journeys in a single test and is available for browser load testing only. Browser tests are not adjusted, so the VUH for a multi-scenario test is the sum of each scenario’s VUs multiplied by the duration.
The following example shows VUH for a two-scenario browser test running for 10 minutes:
| Scenario | VUs | Duration | VUH |
|---|---|---|---|
| Login flow (Playwright) | 30 | 600s | 30 × 600 ÷ 3,600 = 5.00 |
| Checkout flow (Playwright) | 20 | 600s | 20 × 600 ÷ 3,600 = 3.33 |
| Total | 50 | Â | 8.33 |
For API tests, include multiple traffic mixes as thread groups within your JMeter test plan. BrowserStack does not treat these as separate scenarios. VUH is based on the test’s total VUs, adjusted to engines once using the formula above, not per thread group.
Hybrid tests (API + browser)
A hybrid test has an API component (for example, JMeter) and a browser component (for example, Playwright). Each component is charged against its own quota with its own adjustment rules:
API VUH = Adjusted API VUs × Duration → charged against your API VUH quota
Browser VUH = Browser VUs × Duration → charged against your Browser VUH quota (no adjustment)
For a hybrid test with an 80% API and 20% browser split, 500 total VUs, and a 10-minute duration:
API VUs: 400 → 1 engine → 1,000 adjusted × 600s ÷ 3,600 = 166.67 API VUH
Browser VUs: 100 → 100 actual × 600s ÷ 3,600 = 16.67 Browser VUH
Estimated vs. actual VUH
BrowserStack calculates VUH at two points.
Before the test (estimated)
When you start a test, BrowserStack estimates its VUH from Adjusted VUs and checks it against your remaining quota. If the estimate exceeds your quota, the test is blocked before it starts. The estimate gates the run but is not deducted from your quota at this point.
After the test (actual)
VUH is deducted from your quota only after the test reaches a terminal state. Actual VUH is recorded from real pod lifecycle events:
| Phase | What’s measured |
|---|---|
| Pod creation | Time from pod scheduled to container start |
| Initialization | Time from container start to test init complete |
| Execution | Actual test execution time |
| Shutdown | Time from test end to pod cleanup |
Because actual VUH includes pod startup and shutdown, it can be slightly higher than the execution time alone, typically a few extra seconds per pod. For ramping or spike profiles and for iterations that complete early, actual VUH is often lower than the estimate.
Any test that starts running, including tests that fail, are stopped, errored out, or timed out, consumes VUH. This happens as the pods ran and used compute. Only the tests which were blocked before they started (for example, when the estimate exceeds your quota) consume zero VUH.
Quota and usage warnings
BrowserStack tracks your VUH against your plan quota and warns you as you approach the limit. The following sections explain how quotas are split and when a test is warned or blocked.
Separate quotas for API and browser
API tests and browser tests draw from separate quotas with different adjustment rules:
| Quota | Covers | Adjustment |
|---|---|---|
| API VUH | k6, JMeter, Gatling, Locust | Adjusted to 1,000 VUs per engine |
| Browser VUH | Playwright, Selenium, WebdriverIO, Nightwatch | None (1 VU per pod) |
80% usage warning
When a test run would push your usage past 80% of a VUH quota, you see a warning. The check is evaluated separately for your API and browser quotas. This is an early heads-up, it does not block the test.
Quota exceeded
If the estimated VUH exceeds your remaining quota, the test is blocked before it starts.
Your VUH quota resets on a 30-day rolling window from your plan start date. Check your current consumption and reset date in Settings > Usage in the Load Testing dashboard. See the FAQs for more on quotas and test limits.
Quick reference
This table summarizes the most common VUH questions:
| Question | Answer |
|---|---|
| What’s the formula to calculate VUH? |
ceil(VUs / 1,000) × 1,000 × Duration ÷ 3,600 for API tests |
| What is the per-engine capacity? | 1,000 VUs, the fixed capacity reserved per engine |
| Why is my VUH higher than VUs × Duration? | Each engine reserves full capacity. 500 VUs still uses one full engine (1,000 VUs). |
| Does specifying an engine count affect VUH? | Yes, for JMeter, an explicit engine count overrides auto-calculation and can increase VUH (max 10 engines). |
| Does a region split affect VUH? | Yes, each region runs on at least one engine, which can increase total engines and VUH. |
| Are API and browser VUH separate? | Yes, separate quotas with different adjustment rules. |
| Are browser tests adjusted? | No, browser tests use actual VUs (1 VU per pod). |
| Do failed or stopped tests consume VUH? | Yes, any test that runs consumes VUH. Only tests blocked before they start consume none. |
| When does the quota reset? | On a 30-day rolling window from your plan start date. |
What’s next
- Load profiles — understand constant, ramping, spike, and iteration profiles.
- FAQs — quotas, test limits, and reset windows.
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
Thank you for your valuable feedback!