BabylonJS/Babylon.js · error

WebXR not supported on this browser.

Error message

WebXR not supported on this browser.

What it means

initializeAsync() checks for the WebXR API (navigator.xr). If the browser (or the current context, e.g. non-secure origin or an unsupported environment) does not expose navigator.xr, WebXR is simply unavailable and the manager throws immediately instead of starting a doomed session.

Source

Thrown at packages/dev/core/src/XR/webXRSessionManager.ts:345

        if (this._xrNavigator.xr.native) {
            return new NativeXRRenderTarget(this);
        } else {
            options = options || WebXRManagedOutputCanvasOptions.GetDefaults(engine);
            options.canvasElement = options.canvasElement || engine.getRenderingCanvas() || undefined;
            return new WebXRManagedOutputCanvas(this, options);
        }
    }

    /**
     * Initializes the manager
     * After initialization enterXR can be called to start an XR session
     * @returns Promise which resolves after it is initialized
     */
    public async initializeAsync(): Promise<void> {
        // Check if the browser supports webXR
        this._xrNavigator = navigator;
        if (!this._xrNavigator.xr) {
            throw new Error("WebXR not supported on this browser.");
        }
    }

    /**
     * Initializes an xr session
     * @param xrSessionMode mode to initialize
     * @param xrSessionInit defines optional and required values to pass to the session builder
     * @returns a promise which will resolve once the session has been initialized
     */
    public async initializeSessionAsync(xrSessionMode: XRSessionMode = "immersive-vr", xrSessionInit: XRSessionInit = {}): Promise<XRSession> {
        // A WebGPU engine requires a WebGPU-compatible XR session (per the WebXR/WebGPU binding spec).
        // The "webgpu" feature descriptor is requested as a *required* feature: a WebGPU engine cannot
        // fall back to a WebGL-compatible session, so if the UA/device cannot provide one we let
        // requestSession reject and surface that error to the caller rather than silently handing back
        // an incompatible session. WebGL engines leave xrSessionInit untouched.
        if (this._engine?.isWebGPU) {
            const requiredFeatures = xrSessionInit.requiredFeatures ? [...xrSessionInit.requiredFeatures] : [];
            if (!requiredFeatures.includes("webgpu")) {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Serve the page over HTTPS (or localhost) so navigator.xr is exposed.
  2. Feature-detect first: `if (!('xr' in navigator))` and show a fallback UI / use Babylon's WebXRExperienceHelper fallback instead of calling initializeAsync.
  3. Use a browser that supports WebXR (Chrome/Edge with a headset or Emulator) and enable the required flags.
  4. For iframes, add `<iframe allow="xr-spatial-tracking ...">` and the correct Permissions-Policy header.
  5. On unsupported platforms, fall back to non-XR rendering (camera + device orientation) or a polyfill-based UX.

Example fix

// before
const xr = new WebXRSessionManager(scene);
await xr.initializeAsync(); // throws on Safari
// after
if ('xr' in navigator) {
  const xr = new WebXRSessionManager(scene);
  await xr.initializeAsync();
} else {
  showNonXRWarning(); // fallback experience
}
Defensive patterns

Strategy: fallback

Validate before calling

if (!('xr' in navigator)) {
  showFallbackExperience();
  return;
}
const xr = new WebXRSessionManager(scene);
await xr.initializeAsync();

Type guard

function webxrSupported(): boolean {
  return typeof navigator !== 'undefined' && 'xr' in navigator && navigator.xr != null;
}

Try / catch

try {
  await xr.initializeAsync();
} catch (e) {
  if (e instanceof Error && e.message === 'WebXR not supported on this browser.') {
    showUnsupportedBrowserDialog();
    startNonXRFallback(scene);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Running in a browser without WebXR support (Safari, Firefox desktop, older Chrome); opening the page over plain http instead of https (WebXR is gated to secure contexts); using an emulator/iframe without xr-spatial-tracking permissions; WebXR disabled in browser flags.

Common situations: Testing on a desktop browser without a headset/emulator; iOS Safari which lacks WebXR entirely; missing the `xr-spatial-tracking` Feature-Policy/Permissions-Policy header when embedding in an iframe; outdated browser version.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/d02475a4b036a5c0. Report an issue: GitHub.