Multi-engine routing
WebX treats a browser engine as replaceable execution infrastructure. The control plane chooses the lowest-cost compatible backend while preserving WebX policy, evidence, lifecycle, identity, quota, and human-control semantics.
This is intentionally different from treating every CDP-speaking product as Chromium. Agent-first engines such as Kitesurf, Lightpanda, and Obscura can be excellent for bounded extraction, but their CDP and Web Platform surfaces are not interchangeable with full Chrome.
Safety contract
- The primary engine is used when a request declares no requirements and its launch configuration implies none. This preserves existing behavior.
- Explicit
required_capsare merged with requirements inferred from the authoritative launch configuration. Callers cannot omit capabilities to make WebX ignore a proxy, persistent profile, extension, custom binary, or high-assurance isolation request. - Only failures classified as pre-execution
capacityorunavailablemay try the next compatible engine. - Unknown and incompatible provisioning failures stop immediately.
- WebX never replays an already-started browser task on another engine. That would duplicate side effects. A future runtime escalation feature must use checkpoints/effect contracts and explicit operator policy.
- Engines that fail the startup live-conformance probe are not registered or
advertised by
GET /api/engines.
Every successful allocation exposes the selected engine, routing reason, and
redacted attempts in session metadata and the API response. WebX also emits an
webx.engine-selection.v1 operational evidence event with
runtimeFallbackAllowed: false when the configured evidence store accepts it.
Capability model
The engine profile separates one-shot rendering from full-browser behavior:
- DOM/WebMCP/accessibility/pixel perception modes;
- live screencast, screenshot, and PDF;
- proxy and authenticated
Fetchinterception; - persistent contexts and long sessions;
- extensions and Selenium;
- WebGL, media, and downloads;
- launch-flag control and high-assurance isolation;
- real-browser fingerprint fidelity.
New fields deserialize to false. Older capability JSON therefore remains
readable and fails closed instead of receiving newly introduced powers.
Full Chromium enables the complete profile. A Kitesurf-class profile enables
one-shot DOM, screenshot, and PDF work but not persistent auth, Selenium,
extensions, media/WebGL, bot-sensitive fingerprint fidelity, or long sessions.
Live probes verify Fetch.enable, Page.startScreencast,
Page.captureScreenshot, and Page.printToPDF; unprobeable capabilities stay
bound to the known engine family.
Registering engines
External unauthenticated DevTools discovery endpoints use:
WEBX_ENGINES="extract-a=http://10.0.0.21:9222;extract-b=http://10.0.0.22:9222"
Each direct endpoint is single-tenant because WebX does not control its process or browser contexts. Register one endpoint per desired concurrent session. Launch-time configuration is rejected on direct endpoints rather than ignored.
Cloudflare Browser Run/Kitesurf currently requires a provider-specific
authenticated CDP transport. Do not place credentials in WEBX_ENGINES. Add a
credential-vault-backed adapter, region policy, and tenant opt-in before using
it for customer traffic. Kitesurf is also beta; Chromium must remain the
full-fidelity route.
API
POST /api/sessions accepts required_caps. Example one-shot screenshot:
{
"required_caps": {
"screenshot": true
}
}
The response reports what actually happened:
{
"engine": "extract-a",
"routing_reason": "safe_allocation_fallback",
"routing_attempts": [
{"engine":"extract-b","outcome":"capacity"},
{"engine":"extract-a","outcome":"selected"}
]
}
Browserbase-compatible responses expose the same fields under webx. The
engine label is operator configuration, while metrics normalize it to a bounded
family so arbitrary labels cannot create unbounded Prometheus cardinality.
Observability
GET /api/engines— registered, live-probed capability profiles.webx_engine_selection_total{engine_family,reason}— selected engines.webx_engine_allocation_retry_total{engine_family,outcome}— safe pre-execution capacity/unavailability retries.- Evidence kind
engine_selection— per-session operational explanation; session metadata remains the authoritative routing record. - Admin Console → Engines — stateful/stateless posture and important capabilities.
Production rollout
- Keep Chromium primary.
- Register a lightweight canary engine with isolated capacity.
- Send only explicit DOM/screenshot/PDF workloads to it.
- Compare success, wall time, cost, and fallback rate against Chromium using the scenario lab.
- Maintain per-domain compatibility data. Do not infer universal compatibility from Web Platform Test counts.
- Expand traffic only after the same verification contracts pass on both engines.