Send someone a link, and a VR scene or an AR view can open straight from it. No install, no store listing. That is the whole appeal of WebXR, a web standard that gives pages direct access to VR headsets, AR-capable phones, and their controllers from the browser.
Chrome, Edge, Meta Quest Browser, and Safari on visionOS implement the specification, though each one exposes a different share of its features.
The interface draws nothing on its own. It hands over timing, device pose, and input, and a WebGL library does the drawing (MDN).
On paper, the standard is also unfinished. The newest Candidate Recommendation Draft is dated 9 June 2026, and the specification has not reached W3C Recommendation status (W3C, 2026).
What Is WebXR?
Open an immersive scene from a URL and the browser handles the device side through the WebXR Device API. A page calls it from JavaScript and gets four capabilities, according to MDN:
- Find compatible VR or AR output devices
- Render a 3D scene to the device at the right frame rate
- Mirror the output to a 2D display (optional)
- Create vectors that represent the movement of input controls
The X in XR isn’t part of an acronym. It stands in for virtual, augmented, mixed, and whatever comes next, according to immersiveweb.dev.
MDN is blunt that this is not a rendering technology. It handles timing and viewpoints plus device data, and leaves model loading and drawing to a graphics API.
Think of it the way you’d think of Geolocation or Fetch. It’s a browser API that a page calls when it needs a capability.
Who Maintains WebXR, and How Mature Is the Standard?
The W3C Immersive Web Working Group edits the WebXR Device API. The specification is still a Candidate Recommendation Draft and has not become a finished W3C Recommendation.
Checked in October 2026, the W3C publication history reads like this:
- The First Public Working Draft came out on 5 February 2019
- A Candidate Recommendation Snapshot followed on 31 March 2022
- 24 Candidate Recommendation Drafts appeared between 26 April 2022 and 9 June 2026
- The latest draft listed is dated 9 June 2026
Some 2026 coverage frames Candidate Recommendation as a fresh milestone (VR.org, June 2026). The W3C record dates that step to March 2022, so the recent news is the steady run of drafts, not a change of status.
WebVR came first. The Chrome 77 release notes say WebVR 1.1 was never enabled by default and never ratified, and they scheduled its removal for Chrome 79, the release that shipped WebXR (Chrome for Developers).
WebVR covered VR only, and controllers went through the Gamepad API. WebXR handles VR and AR, and it builds select and squeeze events into the API itself (MDN).
The core specification stays small. Hit test, anchors, depth sensing, hand input, layers, lighting estimation, and DOM overlays each have their own module specification, per MDN’s specification list.
Under the browser, OpenXR is the native runtime standard on some platforms. Chrome uses it on Windows, where VR is on by default, but a runtime is only enabled by default there if it implements the XR_EXT_win32_appcontainer_compatible extension, which Chrome’s sandbox requires (Chromium documentation). On Android, OpenXR is on by default only for Android XR.
How a WebXR Session Works
A page checks navigator.xr, confirms the target mode with isSessionSupported(), and calls requestSession() from a user action. The browser returns an XRSession, the page picks a reference space, and a frame loop then draws the scene from the viewer’s pose on every frame.
Session Modes
The mode string passed to requestSession() decides what the page gets.
Inline sessions render inside a normal page element and need no XR hardware. Several can run at once. Immersiveweb.dev calls this “Magic Window” mode.
The immersive-vr mode takes exclusive control of a headset and replaces the surrounding world, and only one immersive session of any kind can be active at a time (MDN).
Then there’s immersive-ar. It also takes exclusive device access, but it blends the rendered content with the real world. Phones show the result on screen, and camera-based goggles show it per eye.
The session’s environmentBlendMode reports the blend method. It is opaque for VR where the hardware allows, and additive when the hardware requires it.
Reference Spaces and the Render Loop
A reference space sets the origin and floor level that every pose is measured against. MDN lists five types a page can request:
- viewer, which follows the head position and orientation
- local, with its origin near the viewer’s start position
- local-floor, the same but with y at floor level
- bounded-floor, for a limited play area with boundary geometry
- unbounded, for free movement over long distances
Standing VR usually starts with local-floor, because its origin sits at floor height. When the device can’t report the floor, the browser estimates it and rounds the value to limit fingerprinting.
The loop itself is short. The page calls requestAnimationFrame() on the XRSession, receives an XRFrame per callback, and asks it for the viewer pose.
The pose holds one view per eye, and both get drawn into a single framebuffer through an XRWebGLLayer, left eye on the left half and right eye on the right half. Headsets with 6DoF tracking report position as well as the three rotation axes that 3DoF hardware covers.
Security and Permission Requirements
Immersive sessions only start from a user action on a secure context, and the Permissions Policy has to allow XR on top of that.
| Session feature | User consent | Permissions policy |
|---|---|---|
| local-floor | Always required | xr-spatial-tracking |
| hand-tracking | Always required | None listed |
| hit-test | None listed | xr-spatial-tracking |
| depth-sensing | None listed | xr-spatial-tracking |
The page must be served over HTTPS, and requestSession() has to run inside a user event handler, such as a click on an Enter XR button. An embedded iframe needs allow="xr-spatial-tracking" before it can reach the API (immersiveweb.dev).
Failures reject the promise with a DOMException. SecurityError means permission was denied. NotSupportedError points to a device or a required feature that isn’t there, and InvalidStateError means an immersive session is already active or pending.
Chrome on Android XR prompts for permission again when the experience loads on a different domain, according to the Android developer documentation.
WebXR Browser and Device Support as of October 2026
Chromium browsers and Meta Quest Browser have the most complete WebXR support. Safari supports it only on visionOS and, by default, only for VR. Firefox ships it disabled.
| Browser or device | VR sessions | AR sessions | Notes |
|---|---|---|---|
| Chromium browsers (Chrome, Edge) | Yes, Windows with a tethered headset | Yes, Chrome on ARCore phones (Chrome 81+); no AR on desktop Chrome or Edge | Opera and Samsung Internet share the engine |
| Chrome on Android XR | Yes | Yes | Hand input is the default; runs on Samsung Galaxy XR |
| Meta Quest Browser | Yes | Yes, passthrough | Hit test, anchors, hand tracking |
| Safari on visionOS 2 and later | Yes, on by default | No, not by default | Gaze-and-pinch input |
| Safari on iPhone and iPad | No | No | No WebXR Device API |
| Safari on Mac; Firefox on desktop and Android | Disabled by default, behind flags | Disabled by default, behind flags | Not usable without changing browser settings |
Apple took a slower route. On visionOS 1, WebXR sat behind a Safari feature flag. visionOS 2 turned it on by default and added gaze-and-pinch input (UploadVR, 2024).
The AR module is still missing there by default. visionOS 26.5 adds a “WebXR Augmented Reality Module” Safari flag, which is off by default, and at least one developer reported that it still did not enable AR sessions (Apple Developer Forums). Niantic ran into that gap when porting its 8th Wall AR engine to the headset.
Mozilla closed its Firefox Reality headset browser in February 2022, and Igalia’s Wolvic, built on the same code, took over on standalone headsets (TechCrunch, 2022).
Descriptions of Chrome’s support vary. VR.org (April 2026) describes Chrome and Edge as having full WebXR support on desktop and Android.
The Chromium source documentation is more specific. VR over OpenXR is on by default on Windows, AR over OpenXR is off by default, and phone AR comes through ARCore.
Because support splits this way, plan for cross-browser compatibility from the first prototype. Feature-detect with isSessionSupported() and request optional features instead of requiring them.
Input Sources and Optional Features in WebXR
WebXR input falls into two categories, targeting and actions. Features such as hit-test, anchors, and depth-sensing are opt-in modules that the page requests when it creates the session (MDN).
Controllers, Hands and Gaze
Targeting decides what the user is pointing at, and an action fires once something is targeted.
In gaze mode, the target ray starts at the viewer and follows the facing direction. A tracked-pointer ray starts at a controller or tracked hand, and in screen mode it comes from a tap or drag on a phone or tablet.
Actions arrive as events. The primary action sends selectstart, select, and selectend, and the grip action sends squeezestart, squeeze, and squeezeend.
Extra buttons, thumbsticks, and trackpads come through the input source’s gamepad object, which uses the xr-standard mapping.
Hand tracking is a separate optional feature named hand-tracking, and it always needs user consent. Chrome on Android XR makes hand input the default, and Safari on visionOS maps gaze-and-pinch to WebXR input.
AR Modules for Placement and Environment Sensing
The AR modules are all opt-in, and each one solves a specific placement or sensing problem.
- The hit-test module casts a ray against real-world geometry to find a surface. Chrome shipped it for Android in Chrome 81 (web.dev).
- Anchors pin virtual objects to real locations. Meta Quest Browser lets a site create 8 persistent anchors at a time, per Meta’s developer documentation. Persistent anchors on Quest are not kept in private mode, and clearing site history deletes them.
- Depth-sensing returns depth data through XRDepthInformation, in CPU-optimized or GPU-optimized form. Chrome on Android XR supports it.
- Light-estimation gives an estimate of environmental lighting through XRLightEstimate.
- Dom-overlay shows an HTML element over the AR view.
- Layers allows layer types other than the default projection layer.
Request these as optionalFeatures unless the experience breaks without them. A missing requiredFeature makes requestSession() reject with NotSupportedError.
Safari on visionOS offers none of the AR modules by default, because it has no immersive-ar mode by default.
Tools and Frameworks for Building WebXR Experiences
Pick a WebGL-based library instead of writing raw API calls. Three.js suits people who want control, and A-Frame suits markup-driven scenes. Babylon.js and PlayCanvas are full engines, and model-viewer fits the narrow case of placing one 3D model in AR.
Graphics APIs: WebGL and WebGPU
WebGL is the renderer every library below uses, and WebGPU is the one still being specified.
WebGL is the production path, supported by all five tools in the table further down. WebGPU needs a separate binding module that adds XRGPUBinding and a “webgpu” feature descriptor, and the Immersive Web Working Group still publishes it as an Editor’s Draft.
Engines are already building around it. Babylon.js has begun work on a layers-only WebGPU XR path that needs an engine created with xrCompatible: true and the “webgpu” feature, and a WebGPU engine cannot fall back to a WebGL XR session if entry fails.
For client work in October 2026, stay on WebGL. The draft status and that failure mode both argue against a WebGPU-only build, and I wouldn’t ship one yet.
Libraries and Engines
Most WebXR projects land on one of a handful of tools, and the real difference is how much each one hides from you.
| Tool | Approach | Session entry | Best for |
|---|---|---|---|
| Three.js | 3D library | WebXRManager plus VRButton or ARButton | Custom scenes, full control |
| A-Frame | HTML framework on three.js | Built-in VR setup | Fast prototypes |
| Babylon.js | Engine | createDefaultXRExperienceAsync() | Teleportation and pointer selection out of the box |
| PlayCanvas | Engine with editor | app.xr.start() | Editor-driven teams |
| model-viewer | Web component | ar attribute | One model in AR |
Three.js gives the most control. Its documentation lists a WebXRManager on the renderer, VRButton, ARButton, and XRButton helpers, controller and hand model factories, and a depth-sensing class.
- A-Frame builds on three.js and writes scenes as HTML tags. The A-Frame site lists 1.8.0 as the current release.
- Babylon.js has a default experience helper that adds an enter button, controllers, pointer selection, and teleportation. On browsers without XR support the button never appears.
- The PlayCanvas manual’s example checks app.xr.supported, then calls app.xr.start() with a camera entity, XRTYPE_VR, and XRSPACE_LOCALFLOOR.
- @react-three/xr brings React bindings to React Three Fiber. createXRStore() builds the store, and store.enterAR() and store.enterVR() start sessions. The XR component must wrap the scene or nothing happens, even over HTTPS.
PlayCanvas’s manual still describes Vision Pro support as a Safari setting. That conflicts with the on-by-default behavior reported for visionOS 2, so check any library’s documentation against current browser behavior before promising a device.
Placing a Model in AR with model-viewer
model-viewer is a web component, not a WebXR framework, and a single product model needs one HTML tag.
You need a glTF or GLB file for the viewer, and optionally a USDZ file in the ios-src attribute for iPhone and iPad. On Android, the visitor needs an ARCore-supported device with Google Play Services for AR.
The ar-modes attribute decides which AR route handles the model. Its default order is webxr, scene-viewer, quick-look, so on Android, Scene Viewer takes over by default when WebXR is unavailable.
Quick Look on iOS accepts only USDZ. If you supply ios-src, visitors who viewed the GLB in the page download the model a second time. If you leave it out and keep quick-look enabled, model-viewer generates a USDZ on the fly, at lower fidelity and without animations (model-viewer documentation).
How to Start a WebXR Session in Code
A session starts with feature detection and ends in a running frame loop, and the order of the steps in between matters.
- Detect navigator.xr. If it is missing, keep the page as an ordinary 2D or 3D view.
- Call isSessionSupported() with the mode you need, immersive-vr or immersive-ar, and enable the Enter XR button only when the promise resolves true.
- Create a WebGL context and call makeXRCompatible() on it.
- Call requestSession() from the button’s click handler, listing the features the experience needs.
- Attach an XRWebGLLayer through the session’s render state and request a reference space, local-floor for standing VR.
- Start the loop with the session’s requestAnimationFrame(), and listen for the end event so the page can clean up.
The context must be XR-compatible before an XRWebGLLayer can wrap it, which is why step 3 comes before step 5. If you plan to skip a library, learn how WebGL contexts and draw calls behave first.
Testing Without a Headset
An emulator handles desktop Chromium, and a polyfill covers browsers that have no WebXR at all.
Immersive Web Emulator 2.0, a Meta-maintained extension, injects a WebXR runtime into the page, with compatibility on par with Meta Quest Browser for mainstream features. It runs on Chrome, Edge, and other Chromium browsers only.
For everything else there’s the WebXR Polyfill, a JavaScript implementation of the WebXR Device API and the WebXR Gamepad Module. You instantiate it before any XR code runs.
PlayCanvas’s manual warns that the older WebXR API Emulator extension throws an exception in PlayCanvas apps. A team on that engine should install the Immersive Web Emulator and nothing else.
WebXR or a Native App: Which Fits the Project?
Pick WebXR when reach and shareable links matter more than peak graphics, and when store review would only slow you down. Pick native when the scene needs sustained frame rates or hardware access the browser does not expose.
Projects That Fit WebXR

VR.org’s 2026 coverage names the categories where the browser is already good enough:
- Educational content
- Data visualization
- Product configurators
- Collaborative tools
- Quick prototypes
Anything that benefits from a shareable URL belongs on that list. Graphically intensive games do not.
Pros and Cons of Each Option
WebXR has a few clear advantages:
- One build runs on any headset with WebXR support, so there are no per-headset builds to manage (Road to VR, 2024)
- There are no store gatekeepers and no upload step
- Inline sessions give visitors without a headset a normal-screen view, on any browser that implements the API
The downsides are real too. You get less hardware access than a native app, according to VR.org, and MDN labels the API experimental and not Baseline, so production work starts with its compatibility table.
Native apps get deeper hardware access and distribution through headset stores. In return you build separately for each headset, upload and manage on every platform store, and live with store gatekeepers deciding when a fix reaches users.
A Decision Rule
Prototype in WebXR first. If the scene cannot hold the headset’s frame rate after you cut draw calls and texture sizes, build native.
Installing isn’t reserved for native apps. A progressive web app can host the same page, and MDN says a runtime may treat launching one as user intent for requestSession().
Where WebXR Falls Short
WebXR runs into trouble when frame time is tight or a feature is missing on the target browser. It also has its own gap on iPhone and iPad.
Performance Ceiling
Meta’s documentation puts the frame budget at about 13.9 milliseconds for 72 FPS, the browser default on Meta Quest, while Meta Quest 2 defaults to 90 FPS.
Draw calls cost CPU time even when the GPU is idle. Meta’s example is 1000 individual triangles submitted as separate draw calls, which would likely push an app below 72 frames per second.
When a frame is missed, the system compositor invents the missing one. That shows up as stutter and black bars at the sides of the field of view. The way out is to lower the frame rate through Meta’s frame-rate API so the page gets more time per frame, or to cut draw calls.
A scene that fits the budget in a native engine can still miss it in a browser. VIVERSE’s optimization guide points to CPU dispatch overhead on WebGL calls, which limits how many draw calls a page can afford.
Reaching iPhone and iPad
Visitors on iPhone and iPad get AR through Apple’s own formats instead.
AR Quick Look displays USDZ files on iPhone, iPad, and Apple Vision Pro, and websites can link to them (Apple). The HTML model element shows a 3D model directly in the page, and Apple lists it for Safari in visionOS 26.
The Metropolitan Museum of Art produced a USDZ model of a wooden zemi figure for this route, per Apple’s Quick Look gallery.
The cost is usually a second asset. You keep a GLB for WebXR and Scene Viewer, and a USDZ for Apple.
Fallback Limits
The WebXR Polyfill covers browsers with no API, but MDN’s startup guide tells developers to read its README for limitations before relying on it.
Its mobile fallback is built on Google’s Cardboard API, so treat it as a rough substitute for a headset, not an equal one.
Inline sessions keep the scene visible on a normal screen, with viewer tracking only where the device provides it.
WebXR FAQ
Is WebXR the same as OpenXR?
No. WebXR is the browser API that web pages call, while OpenXR is the native standard that engines and runtimes use to talk to headsets.
A browser can translate WebXR calls into OpenXR calls, so a page benefits from both without any OpenXR code.
Do you need a headset to use WebXR?
No. Phones with AR support run immersive-ar sessions, and inline sessions render on an ordinary screen in any browser that implements the API.
Only immersive-vr sessions are built around a headset.
What is the difference between WebXR and WebAR?
WebXR is one specific standard, the WebXR Device API. WebAR is a broader label for any AR that runs from a browser link, including routes that skip WebXR, such as Scene Viewer on Android and Quick Look on iPhone.
Which programming language does WebXR use?
JavaScript. TypeScript works too, since it compiles to JavaScript.
Scenes are drawn with WebGL, so custom shaders are written in GLSL, and A-Frame lets you describe a scene in HTML tags.
Can WebXR content run inside an iframe?
Yes, with a condition. A cross-origin iframe needs the xr-spatial-tracking permission policy, set through the iframe’s allow attribute, before it can start an immersive session.
Without that policy, requestSession() is refused inside the frame.
Is WebXR free to use?
Yes. It is an open W3C standard, so there is no license fee, SDK purchase, or store account to pay for.
Real costs come from 3D asset production, hosting, and testing across browsers and devices.
What It Costs to Keep a WebXR Project Working
Maintaining a WebXR project costs a recurring compatibility check more than a rewrite, because the specification moves in dated drafts and each browser adds modules on its own schedule.
The W3C published 24 drafts between 26 April 2022 and 9 June 2026, which works out to one draft about every two months.
Order the upkeep by how fast each risk moves. Feature detection for every optional module comes first, since that’s where browsers differ most. A real-headset pass after each browser release comes next, and a WebGPU review can wait until its binding changes status.
The price of that routine is a second asset pipeline for Apple devices and one more test target per browser.
As verified on 11 October 2026, the case for building on WebGL ends if the WebXR/WebGPU Binding leaves Editor’s Draft status.
- Figma Keyboard Shortcuts That Will 10x Your Speed - October 25, 2026
- What is Backend in Web Development? - September 13, 2026
- What is Frontend Development? - September 11, 2026


