{"record":{"id":"d02475a4b036a5c0","repo":"BabylonJS/Babylon.js","slug":"webxr-not-supported-on-this-browser","errorCode":null,"errorMessage":"WebXR not supported on this browser.","messagePattern":"WebXR not supported on this browser\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/XR/webXRSessionManager.ts","lineNumber":345,"sourceCode":"        if (this._xrNavigator.xr.native) {\r\n            return new NativeXRRenderTarget(this);\r\n        } else {\r\n            options = options || WebXRManagedOutputCanvasOptions.GetDefaults(engine);\r\n            options.canvasElement = options.canvasElement || engine.getRenderingCanvas() || undefined;\r\n            return new WebXRManagedOutputCanvas(this, options);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Initializes the manager\r\n     * After initialization enterXR can be called to start an XR session\r\n     * @returns Promise which resolves after it is initialized\r\n     */\r\n    public async initializeAsync(): Promise<void> {\r\n        // Check if the browser supports webXR\r\n        this._xrNavigator = navigator;\r\n        if (!this._xrNavigator.xr) {\r\n            throw new Error(\"WebXR not supported on this browser.\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Initializes an xr session\r\n     * @param xrSessionMode mode to initialize\r\n     * @param xrSessionInit defines optional and required values to pass to the session builder\r\n     * @returns a promise which will resolve once the session has been initialized\r\n     */\r\n    public async initializeSessionAsync(xrSessionMode: XRSessionMode = \"immersive-vr\", xrSessionInit: XRSessionInit = {}): Promise<XRSession> {\r\n        // A WebGPU engine requires a WebGPU-compatible XR session (per the WebXR/WebGPU binding spec).\r\n        // The \"webgpu\" feature descriptor is requested as a *required* feature: a WebGPU engine cannot\r\n        // fall back to a WebGL-compatible session, so if the UA/device cannot provide one we let\r\n        // requestSession reject and surface that error to the caller rather than silently handing back\r\n        // an incompatible session. WebGL engines leave xrSessionInit untouched.\r\n        if (this._engine?.isWebGPU) {\r\n            const requiredFeatures = xrSessionInit.requiredFeatures ? [...xrSessionInit.requiredFeatures] : [];\r\n            if (!requiredFeatures.includes(\"webgpu\")) {\r","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/XR/webXRSessionManager.ts#L327-L363","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Serve the page over HTTPS (or localhost) so navigator.xr is exposed.","Feature-detect first: `if (!('xr' in navigator))` and show a fallback UI / use Babylon's WebXRExperienceHelper fallback instead of calling initializeAsync.","Use a browser that supports WebXR (Chrome/Edge with a headset or Emulator) and enable the required flags.","For iframes, add `<iframe allow=\"xr-spatial-tracking ...\">` and the correct Permissions-Policy header.","On unsupported platforms, fall back to non-XR rendering (camera + device orientation) or a polyfill-based UX."],"exampleFix":"// before\nconst xr = new WebXRSessionManager(scene);\nawait xr.initializeAsync(); // throws on Safari\n// after\nif ('xr' in navigator) {\n  const xr = new WebXRSessionManager(scene);\n  await xr.initializeAsync();\n} else {\n  showNonXRWarning(); // fallback experience\n}","handlingStrategy":"fallback","validationCode":"if (!('xr' in navigator)) {\n  showFallbackExperience();\n  return;\n}\nconst xr = new WebXRSessionManager(scene);\nawait xr.initializeAsync();","typeGuard":"function webxrSupported(): boolean {\n  return typeof navigator !== 'undefined' && 'xr' in navigator && navigator.xr != null;\n}","tryCatchPattern":"try {\n  await xr.initializeAsync();\n} catch (e) {\n  if (e instanceof Error && e.message === 'WebXR not supported on this browser.') {\n    showUnsupportedBrowserDialog();\n    startNonXRFallback(scene);\n    return;\n  }\n  throw e;\n}","preventionTips":["Feature-detect navigator.xr before any XR code path","Serve over HTTPS — WebXR requires a secure context","Add xr-spatial-tracking to iframe allow/Permissions-Policy attributes","Provide a non-XR fallback (orbit camera / device-orientation) for unsupported browsers","Test on target browsers early (Safari/iOS lacks WebXR)"],"tags":["webxr","browser-support","secure-context"],"backgroundTag":"webxr-unsupported-browser","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}