Other

Building VR and AR Features With the MERN Stack (WebXR and React Three Fiber)

image 9 Building VR and AR Features With the MERN Stack (WebXR and React Three Fiber)
On this page
  1. VR, AR and WebXR in plain English
  2. Real use cases for MERN apps
  3. The frontend toolkit
  4. A 3D product scene with VR and AR buttons
  5. The simplest AR: model-viewer
  6. The backend: storing 3D assets with MongoDB and Express
  7. Performance: make it work on a real phone
  8. Requirements and testing
  9. Is it worth building?
  10. Tracking whether 3D and AR help
  11. Frequently asked questions
  12. Oh hi there 👋It’s nice to meet you.
  13. Sign up to receive awesome content in your inbox.

Virtual reality (VR) and augmented reality (AR) no longer require native apps. Modern browsers support WebXR, a standard that lets a web page show 3D content in a VR headset or place virtual objects into the real world through a phone’s camera. That means the MERN stack you already know can power immersive features: React draws the 3D scene, Express serves the data, and MongoDB stores your products, scenes and 3D assets.

This guide shows the practical pieces: the libraries to use, a working React example, an AR product preview, the backend for 3D assets, and the performance work that makes it all usable on real devices.

VR, AR and WebXR in plain English

Term Meaning Typical device
VR (virtual reality) You are fully inside a 3D world Headsets such as Meta Quest
AR (augmented reality) Virtual objects appear on top of the real world Phones, some headsets in passthrough mode
WebXR The browser API that gives web pages access to VR and AR devices Supported browsers on headsets and Android phones
glTF / GLB The standard file format for 3D models on the web Exported from Blender and most 3D tools
USDZ Apple’s 3D format used for AR Quick Look on iPhone and iPad iOS devices

Device support is the first thing to plan around. Headset browsers, such as the one on Meta Quest, support immersive VR. Chrome on many Android phones supports WebXR AR. Safari on iPhone doesn’t support WebXR AR sessions; instead, iPhones show AR through AR Quick Look with a USDZ file. Fortunately, the tools below handle these differences for you.

Real use cases for MERN apps

  • E-commerce: “view in your room” for furniture, decor, shoes or electronics, so buyers see the real size before ordering.
  • Real estate and hotels: virtual walkthroughs of properties and rooms.
  • Education: 3D models of molecules, machines or the solar system that students can explore.
  • Training: step-by-step procedures in VR, from equipment handling to safety drills.
  • Events and showrooms: virtual exhibition stands that visitors explore from a browser.

The frontend toolkit

  • Three.js: the most widely used 3D library for the web.
  • React Three Fiber (R3F): lets you build Three.js scenes with React components, state and hooks.
  • @react-three/drei: ready-made helpers such as camera controls, model loading and environment lighting.
  • @react-three/xr: adds VR and AR sessions, controllers and hand tracking to R3F scenes.
  • <model-viewer>: Google’s web component for showing a 3D model with one HTML tag, including AR on Android and iPhone.
npm install three @react-three/fiber @react-three/drei @react-three/xr @google/model-viewer

A 3D product scene with VR and AR buttons

Here is a React component that shows a product model you can rotate, with buttons to enter VR or AR on supported devices:

import { Canvas } from '@react-three/fiber';
import { OrbitControls, Environment, useGLTF } from '@react-three/drei';
import { XR, createXRStore } from '@react-three/xr';
import { Suspense } from 'react';

const store = createXRStore();

function ProductModel({ url, scale = 1 }) {
  const { scene } = useGLTF(url);
  return <primitive object={scene} scale={scale} position={[0, 0, -1.5]} />;
}

export default function ProductViewer({ model }) {
  return (
    <>
      <div className="xr-buttons">
        <button onClick={() => store.enterVR()}>View in VR</button>
        <button onClick={() => store.enterAR()}>View in AR</button>
      </div>
      <Canvas camera={{ position: [0, 1.2, 2] }} style={{ height: 480 }}>
        <XR store={store}>
          <Suspense fallback={null}>
            <ProductModel url={model.glbUrl} scale={model.scale} />
            <Environment preset="apartment" />
          </Suspense>
          <OrbitControls target={[0, 0, -1.5]} />
        </XR>
      </Canvas>
    </>
  );
}

Outside a headset, the scene renders normally in the page and users rotate the product with the mouse or a finger. On a device that supports WebXR, the buttons start an immersive session. The Suspense boundary keeps the page responsive while the model downloads. Library APIs in this space change between major versions, so check the current @react-three/xr documentation when you start a project.

The simplest AR: model-viewer

For product previews, you often don’t need a custom 3D scene at all. <model-viewer> gives you rotation, zoom and AR on both Android and iPhone with one element:

import '@google/model-viewer';

export function ArPreview({ product }) {
  return (
    <model-viewer
      src={product.model.glbUrl}
      ios-src={product.model.usdzUrl}
      alt={`3D model of ${product.title}`}
      ar
      ar-modes="webxr scene-viewer quick-look"
      ar-scale="fixed"
      camera-controls
      auto-rotate
      poster={product.model.posterUrl}
      style={{ width: '100%', height: '420px' }}
    />
  );
}

On Android, the AR button places the model in the room through WebXR or Google’s Scene Viewer. On iPhone, it opens AR Quick Look using the USDZ file. ar-scale="fixed" keeps the model at its real size, which matters for furniture and products where size is the whole point. The poster image shows instantly while the model loads.

The backend: storing 3D assets with MongoDB and Express

3D files are large, often several megabytes, so don’t store them in MongoDB documents. Store the files in object storage such as S3, Cloudflare R2 or Cloudinary, serve them through a CDN, and keep the metadata in MongoDB:

// models/Product.js
const productSchema = new mongoose.Schema({
  title: { type: String, required: true },
  slug: { type: String, required: true, unique: true },
  price: { type: Number, required: true },
  model: {
    glbUrl: String,        // CDN URL of the compressed GLB file
    usdzUrl: String,       // for iPhone AR Quick Look
    posterUrl: String,     // still image shown while loading
    scale: { type: Number, default: 1 },
    sizeKb: Number,
    dimensionsCm: { width: Number, height: Number, depth: Number },
  },
}, { timestamps: true });
// routes/products.js
router.get('/:slug', async (req, res) => {
  const product = await Product.findOne({ slug: req.params.slug }).lean();
  if (!product) return res.status(404).json({ message: 'Product not found' });
  res.set('Cache-Control', 'public, max-age=300');
  res.json(product);
});

Uploading a new model from an admin panel follows the usual pattern: the browser uploads the file to object storage (often with a pre-signed URL from your Express API, so files don’t pass through your server), then the API saves the resulting URLs on the product. Validate file type and size on upload, because a 200 MB model will ruin the experience on a phone.

The dimensionsCm field is worth storing even though the 3D file contains geometry: you can show “W 80 × H 95 × D 70 cm” next to the viewer, and use it to check that a model’s scale looks right before publishing.

Performance: make it work on a real phone

3D is heavy, and most visitors use mid-range phones on mobile data. These steps make the biggest difference:

  • Compress models. Tools such as gltf-transform can apply mesh compression (Draco or Meshopt) and shrink textures, often cutting file size dramatically. Example: npx @gltf-transform/cli optimize input.glb output.glb --texture-compress webp.
  • Keep textures reasonable. 1024×1024 or 2048×2048 textures are plenty for most products; 4K textures mainly cost download time and memory.
  • Reduce polygons for anything that doesn’t need fine detail up close.
  • Lazy-load the viewer. Load the 3D libraries only when the user scrolls to the viewer or taps “View in 3D”, with React.lazy(), so product pages stay fast for everyone else.
  • Serve from a CDN with long cache headers, and use versioned file names so updated models aren’t stuck in caches.
  • Show a poster image first, so the page never looks empty while the model loads.

Requirements and testing

HTTPS is required. Browsers only allow WebXR and camera access on secure origins. During development, localhost counts as secure on your computer, but to test on a phone or headset you need HTTPS, for example through a tunnel. See how to share your localhost for the quickest options.

Test on real devices. Browser emulators help with layout, but scale, lighting and performance only show up on actual phones and headsets. The Immersive Web Emulator browser extension can simulate a headset during development, which speeds up the early work.

Design for comfort and access. In VR, avoid moving the camera without user input, because it causes motion sickness. Keep text large and high-contrast. And always offer a normal 2D view with full product information, since many users can’t or won’t use VR or AR.

Is it worth building?

For most MERN projects, start small: a <model-viewer> preview on your best-selling products is a few hours of work and gives shoppers a genuinely useful feature. Measure whether people use it and whether it affects returns or conversions. Move on to custom React Three Fiber scenes and full VR experiences when you have a clear use case, such as training or virtual showrooms, where immersion is the product rather than an extra.

Tracking whether 3D and AR help

Immersive features take effort, so measure their impact like any other feature. Log a few simple events from React to your Express API or analytics tool: when the 3D viewer loads, when someone rotates the model, and when they tap “View in AR”. Store them in a small MongoDB collection with the product id and a timestamp. A weekly aggregation then shows which products get the most AR views, and you can compare conversion and return rates for products with and without 3D previews. Those numbers tell you whether to add models for more products, or to invest the time elsewhere.

Frequently asked questions

Do I need a VR headset to develop WebXR apps?

Not to start. You can build and test the 3D scene in a normal browser and use an emulator extension for headset features. You do need real devices before launch, to check comfort and performance.

Does AR work on iPhone?

Yes, through AR Quick Look with a USDZ file rather than through WebXR. <model-viewer> handles this automatically when you provide the ios-src attribute.

Where do I get 3D models of my products?

From your manufacturer, from 3D artists, or by 3D scanning with photogrammetry apps. Export to glTF/GLB for the web, and convert to USDZ for iPhone AR.

Can I store 3D models in MongoDB?

You can with GridFS, but object storage with a CDN is faster and cheaper for large files. Keep metadata and URLs in MongoDB and the files themselves in storage.

logo

Oh hi there 👋
It’s nice to meet you.

Sign up to receive awesome content in your inbox.

We don’t spam! Read our privacy policy for more info.

Saurabh

Saurabh Pathak is an AI engineer and MERN stack developer, and the founder of mernstackdev.com. He builds open-source projects such as the Haat gateway and MCP safety tooling, and he writes hands-on tutorials on React, Node.js, MongoDB and AI agents. He cares most about code that works in production.

1 comment

  1. Pingback: iphone duo review