Browser & device configuration
Choosing a browser engine, viewport and device profile, what emulation does and does not prove, timeouts, and real Chrome mode.
Each test carries a config that decides where it runs: which browser engine, at what size, on what device, headed or headless, and how long a step may take.
Browser
Three engines, all real browsers:
browser | Engine |
|---|---|
chromium | Chromium (the default) |
firefox | Firefox |
webkit | WebKit — the engine behind Safari |
WebKit is the one worth running deliberately. It is the closest you get to Safari without a Mac, and it is where layout and date-parsing differences actually show up.
Viewport
A width and a height in CSS pixels. Three presets are built in:
| Preset | Size |
|---|---|
desktop | 1280 × 720 |
tablet | 768 × 1024 |
mobile | 390 × 844 |
A test can also list several viewports and be run across all of them, which is how one test covers a responsive layout instead of three near-identical copies.
Changing a test's viewport invalidates its visual baselines — a screenshot is only comparable to a capture at the same size. See Visual regression.
Device emulation
Setting a device picks a Playwright device profile, which overrides the browser
type and viewport together and adds the right user agent, scale factor and touch
support. Seventeen profiles:
Phones — iPhone 15 Pro Max, iPhone 15 Pro, iPhone 15, iPhone 14, iPhone SE (3rd gen), Galaxy S24, Galaxy A55, Pixel 7, Pixel 5
Tablets — iPad Pro 11, iPad (gen 11), iPad Mini, Galaxy Tab S9
Desktop — Desktop Chrome, Desktop Safari, Desktop Firefox, Desktop Chrome HiDPI
A device profile is emulation, not a real device: it is a real browser engine with a phone's viewport, user agent and touch input. It catches responsive layout and touch-target problems. It does not catch iOS Safari's actual quirks, real device performance, or anything involving the platform itself — for that you need native mobile runs.
Because a device sets the browser type, device and browser do not combine: the
device wins.
Headless
Headless is the default and is what you want almost always — it is faster and it is what CI runs. Headed mode is for watching a test to understand why it does something unexpected.
Timeout
The per-step timeout in milliseconds. It bounds how long a step waits for its element or navigation before failing.
Raising it globally to fix one slow step is the wrong lever: it makes every genuine
failure take that much longer to report. Prefer an explicit wait for the thing you
are actually waiting for.
Real Chrome mode
Ordinary Chromium is detectable — bot-detection and WAF layers can tell, and some apps behave differently or block the run outright. Real Chrome mode launches the system-installed Google Chrome instead, with a matching user agent. It is the Real browser switch in the test builder's config panel.
Use it when a target actively fights automation. It requires Google Chrome installed on the machine running the test, so it is a local/self-hosted option rather than something that works on any runner. It also does not combine with device emulation — a device profile already dictates the browser and user agent.
Real Chrome runs headed, not headless: headless Chrome is reliably fingerprinted
even with stealth flags, which is the whole reason the mode exists. It launches with
--disable-blink-features=AutomationControlled and patches navigator.webdriver, and
it draws a visible cursor so you can watch what the run is doing.
Testing behind captchas and bot protection
Vera does not solve captchas, and it is not going to. Every major vendor forbids it in their terms, and a captcha a script can pass is not protecting anything — the feature you would be asking for is one that makes your own bot defence untrue.
What Vera does is help the challenge never appear. In order of how well it works:
1. Turn the captcha off in the environment you test
This is the real answer, and it is the one almost every team ends up with. Captchas are nearly always behind a flag — an environment variable, a feature toggle, a per-tenant setting. Turn it off in staging, in your preview environments, and in whatever localhost stack the local agent drives, and leave it on in production, where it belongs.
Keep the list of environments where it is off written down and short. A captcha quietly disabled on something public is a worse outcome than a test suite that cannot log in.
2. Use the vendor's test keys
Google reCAPTCHA publishes a site/secret key pair that always passes verification and always returns a "this is a test" warning in the widget. hCaptcha and Cloudflare Turnstile publish equivalents. Check the current pairs in the vendor's own documentation rather than copying them out of a blog post — they are the sort of thing that gets rotated.
Two things to be clear about. The secret key is the half that matters: it makes server-side verification succeed unconditionally, so a deployment carrying it has no bot protection at all. And a test key changes nothing about the form itself — your test still has to click or check whatever the widget renders, exactly as a person would.
3. Real browser mode, as a fallback
When you cannot change the environment — a third-party sandbox, a vendor's staging system — turn on Real Chrome mode. A challenge that never fires is a challenge you never have to handle, and running the system's own Chrome, headed, with the automation flags off is what usually gets you there.
Treat it as a fallback rather than a fix. It reduces the odds; it does not remove them, it needs Chrome on the machine running the test, and it rules out device emulation. A WAF that fingerprints on IP or on request timing will still see a datacentre making a burst of requests.
If the challenge appears anyway
There is no captcha-specific error. The step waiting for the element behind the challenge times out like any other step, and the screenshot and video attached to the failure are what tell you a challenge is what you hit — so look at the artifacts before assuming your selector broke.
Two smaller things worth knowing:
- Recording through a challenge does not fill your test with junk navigations.
The recorder strips query parameters when it deduplicates navigations and debounces
rapid redirect chains, so a Cloudflare challenge → redirect → real page sequence
records as one
goto. - A captcha on the login form need not block you. The project's api-login capture
posts credentials directly with Playwright's request context and never renders the
form, so if the endpoint itself is not captcha-verified the whole problem
disappears. See Variables for how the role's
{{email}}and{{password}}reach your steps.
Engine: Playwright or WebDriver
By default tests execute through the in-process Playwright driver. A test (or an environment) can instead select the WebDriver engine and run against a Selenium grid or standalone server. Native mobile uses Appium.
That is a bigger choice than a config flag — the capability matrix differs between engines. See Test engines.
Where config is resolved
Values are layered, later winning:
- The test's own config.
- The named environment the run targets — this is what lets one test run against staging and production without editing it.
- Suite-level matrix cells, when a suite runs a device × browser matrix (see Suites & the run matrix).
Concurrency
Browsers are pooled and capped process-wide, so a large batch queues rather than launching fifty browsers and exhausting the machine. Batch concurrency is configurable per run within the plan's limit.
See also
- Test engines — Playwright vs WebDriver vs Appium, in detail
- Suites & the run matrix — running one suite across many configs
- iOS native testing — real simulators rather than emulation
- Visual regression — why viewport changes reset baselines