How to embed a 3D model on your website

Quick answer

Load the free, MIT-licensed universal-3d-viewer library with one script tag, then add a <universal-3d-viewer> element with your model’s URL in src. Visitors can rotate, zoom and view the model in AR. Compress the GLB first and add a poster image with lazy loading, so the 3D model does not slow your page down.

What are the ways to embed a 3D model?

There are three common approaches. They differ in who hosts the model, which formats work and how much code you write.

  • A hosted viewer in an iframe. You upload the model to a 3D platform and paste its embed code. Quick, but the model lives on their servers and the player follows their rules.
  • A web component. You add a script tag and an HTML element, and the model stays on your site. Google’s <model-viewer> works this way for glTF and GLB, as does universal-3d-viewer, which also reads CAD and BIM formats.
  • A 3D library such as three.js. Full control, but you build the viewer, controls and loading yourself.
OptionFormatsModel stays on your siteCode neededBest for
Hosted viewer (iframe)Set by the platformNoPaste an iframePortfolios and quick shares
<model-viewer>glTF and GLBYesOne script tagProduct pages with GLB models
universal-3d-viewerGLB, glTF, STL, OBJ, FBX, STEP, IFC and moreYesOne script tagStores, documentation, CAD and BIM content
three.js or another 3D libraryAny it has a loader forYesYou write the viewerCustom 3D experiences

The rest of this guide uses universal-3d-viewer, the free, MIT-licensed library behind the MicroPlugins 3D Viewer. Its source is public.

How to embed a 3D model with one script tag

  1. Get the model ready as a GLB GLB is the web’s standard 3D format. Convert other formats with the 3D Converter, then shrink the file with the 3D Compressor.
  2. Upload the model file Put the GLB on your own site or a CDN. If it lives on another domain, that server must allow cross-origin requests (CORS).
  3. Add the script tag Load the viewer library from jsDelivr with one <script> tag. It registers the <universal-3d-viewer> element.
  4. Place the element Add <universal-3d-viewer> where the model should appear and set src to your model URL.

Here is the whole embed:

<script src="https://cdn.jsdelivr.net/npm/universal-3d-viewer@0.2.0/dist/library/universal-3d-viewer.umd.js"></script>
<universal-3d-viewer
  src="/model.glb"
  camera-controls
  asset-base-path="https://cdn.jsdelivr.net/npm/universal-3d-viewer@0.2.0/public/"
></universal-3d-viewer>

The element is full width and 400 px tall by default. Change its size with CSS, like any block element:

universal-3d-viewer {
  height: 500px;
}

The script is the UMD bundle, with three.js inside. Do not load the package’s ES module build with <script type="module">: it imports three by name, which a browser cannot resolve without an import map.

What asset-base-path does

Some models need extra decoder files that are not inside the script: the Draco and Basis decoders, and the WebAssembly engines for CAD and BIM formats. asset-base-path tells the viewer where the draco/, basis/ and wasm/ folders are.

  • Plain GLB and glTF need none of these files.
  • Draco-compressed GLB, KTX2 textures, STEP and IFC do. Without the right path, the decoders fail to load.
  • With the CDN script, point it at the package’s public/ folder on jsDelivr, as in the snippet above.
  • Self-hosting? Copy those three folders from the package to your server and point asset-base-path at them.

Set it before the element starts, since the viewer reads it once.

How to install it from npm

For a site built with Vite, Next.js, Nuxt or another bundler, install the package with three, which it uses as a peer dependency:

npm install universal-3d-viewer three
// Registers the <universal-3d-viewer> element
import 'universal-3d-viewer'

// Or create a viewer from script
import { Universal3DViewer, isAbortError } from 'universal-3d-viewer'

const viewer = new Universal3DViewer({
  container: document.getElementById('viewport'),
  // Where the draco/, basis/ and wasm/ folders are served from
  assetBasePath: '/decoders/',
})

viewer.load('/model.glb').catch((err) => { if (!isAbortError(err)) throw err })

The package is ES modules only. From CommonJS, use await import('universal-3d-viewer'). If you draw your own controls, the universal-3d-viewer/core entry is a smaller build with no element, no built-in UI and no exporters.

See every attribute, event and method

The developer docs cover the web component, the JavaScript API and plugins.

Which attributes should you use?

These are the attributes most embeds need. The developer docs list every other option, from camera limits to hotspots.

AttributeWhat it doesUse it when
posterShows an image until the 3D model is readyAlways, for a fast first paint
loading="lazy"Starts the 3D engine only when the viewer scrolls into viewThe viewer is below the fold
altLabels the model for screen readersAlways
camera-controlsLets visitors rotate, pan and zoomAlmost always
touch-action="pan-y"Lets vertical swipes scroll the page on phonesThe viewer sits in the middle of an article
arShows an AR button on devices that support ARProducts people want to see in their room
auto-rotateTurns the model slowly when nobody is dragging itHero displays, not next to text
up-axis="z"Stands Z-up models uprightCAD models that load lying on their side
generate-schemaAdds schema.org 3DModel data for search enginesPages you want indexed as carrying a 3D model
<universal-3d-viewer
  src="/models/chair.glb"
  poster="/models/chair-poster.webp"
  alt="Oak dining chair"
  loading="lazy"
  camera-controls
  touch-action="pan-y"
  ar
  asset-base-path="https://cdn.jsdelivr.net/npm/universal-3d-viewer@0.2.0/public/"
></universal-3d-viewer>

How to keep the page fast

  • Compress the GLB first. Textures are often most of a model’s weight. The 3D Compressor shrinks textures and geometry in your browser, and our guide to reducing 3D model file size explains the trade-offs.
  • Always set a poster. Visitors see an image at once, and the page’s largest paint does not wait for WebGL.
  • Load lazily. With loading="lazy", nothing 3D starts until the viewer is on screen. With reveal="manual", it waits until the visitor clicks the poster.
  • Publish GLB, not CAD files. A STEP or IFC model makes every visitor download a CAD or BIM engine of several megabytes. Convert STEP to GLB or IFC to GLB before you publish.
  • Idle costs nothing. The viewer only draws when something changes, and it stops while it is scrolled out of view or the tab is hidden.

How to add AR (view in your room)

Add the ar attribute and the viewer shows an AR button on devices that can use it. On Android it opens the model in the browser with WebXR, or in Google Scene Viewer. On iPhone and iPad it opens Apple’s AR Quick Look.

AR Quick Look needs a USDZ file. You can leave that to the viewer, which builds one from the loaded model, or supply your own with ios-src. The GLB to USDZ converter makes one in your browser.

<universal-3d-viewer
  src="/models/lamp.glb"
  ios-src="/models/lamp.usdz"
  camera-controls
  ar
  ar-placement="floor"
  ar-scale="fixed"
></universal-3d-viewer>

Use ar-placement="wall" for things that hang on a wall. ar-scale="fixed" keeps the model at true size, so a chair cannot be pinched to the size of a sofa.

How to embed a 3D model in WordPress

You do not need a plugin. In the block editor, add a Custom HTML block and paste the snippet, with your own model and poster URLs:

<script src="https://cdn.jsdelivr.net/npm/universal-3d-viewer@0.2.0/dist/library/universal-3d-viewer.umd.js"></script>

<universal-3d-viewer
    src="https://example.com/models/drone.glb"
    asset-base-path="https://cdn.jsdelivr.net/npm/universal-3d-viewer@0.2.0/public/"
    poster="https://example.com/models/drone-thumb.jpg"
    camera-controls
    auto-rotate
    ar
></universal-3d-viewer>

WordPress only keeps script tags for users allowed to post unfiltered HTML, such as administrators. If the viewer disappears when you save, ask an administrator to add the block.

Host the model on your own site if it accepts .glb uploads, or anywhere that serves it over HTTPS with CORS enabled. MicroPlugins WordPress plugins are coming soon.

How to embed a 3D model in Shopify

Shopify stores 3D models as product media, so upload your GLB to the product first. Then add the viewer to your Online Store 2.0 theme:

  1. In your Shopify admin, go to Online Store, then Themes, then Edit code.
  2. Under Snippets, add a new snippet named universal-3d-viewer.liquid. Paste in examples/shopify/snippet.liquid from the source repository.
  3. In your product template, such as sections/main-product.liquid, render the snippet where the media appears:
{% render 'universal-3d-viewer', product: product %}

The snippet only renders for products that have a 3D model. It uses the product’s preview image as the poster, loads lazily, turns on AR and can recolour the model when a shopper picks a variant.

If the model does not appear

  • Blank viewer. Check the src URL in a new tab. A model on another domain also needs CORS headers from its server.
  • Compressed or CAD models fail. asset-base-path is missing or wrong, so the decoders cannot load.
  • The model lies on its side. It was made Z-up. Add up-axis="z".
  • The page will not scroll on phones. Add touch-action="pan-y".

Frequently asked questions

Is universal-3d-viewer free for commercial sites?

Yes. It is released under the MIT licence, so you can use it on commercial sites and online stores. Keep the licence notice that ships with the package when you host the files yourself.

Which 3D formats can I embed?

GLB and glTF are best for the web. The viewer also displays STL, OBJ, FBX, PLY, 3MF, STEP, IGES and IFC, among others. The developer docs have the full format list.

Do I need a server to use it?

No backend is needed. The viewer runs entirely in the visitor’s browser. You only need somewhere to host the model file, such as your own site or a CDN, served over HTTPS.

How big should a 3D model be for the web?

As small as it can be while still looking right. Compress textures and geometry before you publish, and add a poster image so visitors see something at once. The 3D Compressor shows the file size before and after.

Does the embedded viewer support AR on iPhone?

Yes. Add the ar attribute. On iPhone and iPad the viewer opens Apple’s AR Quick Look, and it builds the USDZ file that Quick Look needs from your model, unless you supply your own with ios-src.

How is universal-3d-viewer different from model-viewer?

Both are web components you add with a script tag. model-viewer displays glTF and GLB. universal-3d-viewer also opens CAD, BIM and mesh formats such as STEP, IFC, STL and OBJ, and adds CAD edges, clipping and measurement through its API.

Keep reading

Make your model web-ready

Compress the GLB in your browser, then embed it with one script tag.