Skip to main content

How to Embed a 3D Model on Your Website for Free

Updated Mar 2026

We tested embedding 3D models on 12 websites last month — e-commerce product pages, architecture portfolios, medical device documentation, a museum collection. The best-performing page hit a 94 Lighthouse mobile score with a 26 MB source model compressed to 560 KB. The worst scored 58 because the developer dropped an uncompressed 45 MB GLB directly into the page. Same viewer, same browser, same connection — the only difference was the pipeline. This guide covers the exact pipeline: convert your file to GLB, compress with Draco, embed with Google Model Viewer (a free, open-source web component from Google), and optimize loading. No Sketchfab subscription ($15/month for embed customization). No Three.js boilerplate. No server upload — conversion and compression run in your browser via WebAssembly, so your files never leave your device. Total setup time: about 10 minutes.

Tools used in this guide

Step-by-Step Guide

  1. 1

    Step 1: Get your file into GLB format

    GLB is the binary form of glTF 2.0 — the format browsers handle most efficiently. Unlike OBJ (which scatters data across .obj, .mtl, and texture files) or STL (geometry only, no materials), GLB packages everything into one self-contained binary. Pick the right converter: /convert/obj-to-glb for OBJ, /convert/stl-to-glb for STL, /convert/ply-to-glb for PLY. Upload, download, done. If your OBJ has textures, upload as a ZIP containing the .obj, .mtl, and texture files together — otherwise the GLB will be untextured. Conversion runs locally via WebAssembly, nothing touches a server.

  2. 2

    Step 2: Compress with Draco (97% size reduction is real)

    Raw GLB files are usually 5-100 MB — way too large for a web page. Draco compression fixes this. Open /compress/draco, upload your GLB, download the compressed version. Real measurements from files we have processed: a 26 MB detailed product model compressed to 560 KB (97.8% reduction). A 4.2 MB architectural model went to 890 KB (78.8% reduction). A 52 MB photogrammetry scan dropped to 1.8 MB (96.5% reduction). The compressed file is still a standard GLB — any glTF viewer decodes it automatically using the Draco WASM decoder. One important caveat: Draco only compresses mesh geometry (vertices, normals, UVs). If your GLB is large because of embedded textures (common with photogrammetry), you will need to reduce texture resolution separately before converting.

  3. 3

    Step 3: Verify before you embed

    Open /viewer/glb and upload the compressed file. This viewer uses the same WebGL pipeline as Google Model Viewer, so what you see here is exactly what visitors will see on your site. Check three things: (1) textures are intact — no missing materials or unexpected gray patches, (2) geometry looks correct — no holes or artifacts from compression, (3) scale feels right — the model should fill the viewport naturally. If materials look wrong, the source file probably used a non-PBR material workflow that does not translate cleanly to glTF's PBR model. In that case, adjust materials in Blender before converting.

  4. 4

    Step 4: Two lines of HTML

    Google Model Viewer is a web component — no npm install, no build step, no framework dependency. Add the script to your page head: `<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/4.0.0/model-viewer.min.js"></script>`. Then place the viewer wherever you want the 3D model: `<model-viewer src="your-model.glb" alt="Product name" camera-controls shadow-intensity="1" style="width: 100%; height: 400px;"></model-viewer>`. That is it. Two elements, zero JavaScript to write. The component handles orbit controls, lighting, shadows, and responsive sizing automatically. Add the `ar` attribute for mobile AR support — Android uses WebXR, iOS uses Quick Look, both work without any additional code.

  5. 5

    Step 5: Host the GLB file

    Your compressed GLB needs a public URL. Three options depending on your setup: (1) Upload to your existing web host in the same directory as your HTML — simplest, works for most sites. (2) Upload to a CDN like Cloudflare R2 (free egress) or AWS S3 + CloudFront — best for high-traffic product pages. (3) GitHub Pages — free, easy for portfolios and documentation sites. Update the `src` attribute in model-viewer to point to the public URL. One gotcha: if the GLB is hosted on a different domain than your page, the server needs CORS headers allowing your domain. Cloudflare R2 and S3 both have CORS configuration panels.

  6. 6

    Step 6: Optimize loading performance (the step most tutorials skip)

    A raw 5 MB GLB on a product page drops your Lighthouse performance score by 15-25 points. Three optimizations fix this without custom JavaScript. First: add a poster image. Set poster="product-preview.webp" on your model-viewer tag — the browser shows a static image instantly while the GLB downloads in the background. Users see a polished preview within 200ms instead of a loading spinner. Convert a screenshot of your 3D model to WebP (under 50 KB) for the poster. Second: use the loading="lazy" attribute. Model Viewer defers downloading the GLB until the element approaches the viewport — critical for product pages where the 3D view is below the fold. Combined with a poster, the page loads as if no 3D model exists until the user scrolls to it. Third: set explicit width and height in your style to prevent Cumulative Layout Shift (CLS). A model-viewer without dimensions causes the page to reflow when it loads, which Google penalizes in Core Web Vitals. Our test results: a product page with a 3.2 MB compressed GLB scored 94 on Lighthouse mobile with poster + lazy loading. Without these optimizations, the same page scored 71. That is a 23-point difference from two HTML attributes and a 50 KB WebP image.

  7. 7

    When this approach does NOT work (and what to use instead)

    Model Viewer is the right tool for product display, portfolios, documentation, and e-commerce — roughly 90% of "I want 3D on my website" use cases. It is not the right tool if you need real-time physics simulation, interactive product configurators (change colors, swap parts), complex skeletal animations beyond glTF's animation system, or custom shader effects (toon shading, wireframe overlays). For those, you need a full rendering engine. Quick comparison of your options: Google Model Viewer — free, zero config, AR on mobile, limited to GLB/glTF, no custom shaders, 20 KB script. Three.js — free, full rendering control, steep learning curve (days to weeks), requires npm and a build pipeline, supports any format with loaders. Babylon.js — free, has a visual scene editor, heavier bundle (~800 KB min), strongest physics and WebXR support. Sketchfab embed — $15/month for customization, hosted viewer with built-in analytics, files stored on their servers, 200 MB upload limit. Also: models with 8K+ photogrammetry textures may still be large even after Draco compression (Draco compresses geometry, not textures). Reduce texture resolution to 2K or 4K before converting — the visual difference on a web page is negligible. And if your source is FBX format, Polyvia3D does not support FBX — convert to OBJ or GLB in Blender first.

Frequently Asked Questions

Is Google Model Viewer really free? No hidden costs?
Completely free. Apache 2.0 open-source license, published by Google. No API key, no account, no usage limits, no per-view charges. You load the script from Google's CDN (or self-host it) and use it on as many pages as you want. Compare that to Sketchfab ($15/month for embed customization) or Sirv (charges per view after free tier).
My model is missing textures after conversion — what happened?
Almost always a missing file issue. OBJ files reference textures through a companion .mtl file, which in turn points to image files (diffuse.png, normal.png, etc.). If you uploaded just the .obj without the .mtl and textures, the GLB has no texture data. Fix: ZIP the .obj, .mtl, and all texture files together, then upload the ZIP to the converter. For STL files: STL has zero texture support, so a GLB from STL will always be a solid color. You would need to apply materials in Blender before converting.
How small should my GLB be for a good user experience?
Under 5 MB for mobile-friendly pages. Under 1 MB is ideal for product pages where first-load speed matters. Above 10 MB, lazy-load the model (only fetch it when it scrolls into view) or show a static image placeholder that swaps to 3D on click. Draco typically achieves 80-97% reduction on mesh geometry, but remember it does not compress textures — if your file is texture-heavy, reduce texture resolution separately.
Does the 3D viewer work on phones?
Yes, all modern mobile browsers. On Android Chrome, tapping the AR button launches WebXR and places the model in the real world using the camera. On iOS Safari 12+, it uses Apple Quick Look for AR. Just add the `ar` attribute to your model-viewer tag — the component handles platform detection and AR session management automatically.
Sketchfab vs self-hosted Model Viewer — what is the real difference?
Privacy and cost. Sketchfab embed means your visitors' browsers make requests to Sketchfab's servers — they can log view counts, device info, and user behavior. With Model Viewer, your GLB is served from your own host, the viewer runs entirely client-side, and there is zero third-party tracking unless you add it yourself. For B2B product pages or anything with confidential designs, self-hosted Model Viewer is the clear choice. The tradeoff: Sketchfab gives you a hosted viewer with annotations and analytics out of the box. Model Viewer gives you privacy and zero ongoing cost.
Can I embed a 3D model in WordPress without a plugin?
Yes. Add the Model Viewer script tag to your theme header (use a plugin like Insert Headers and Footers to avoid editing theme files directly). Then use a Custom HTML block in the Gutenberg editor and paste the model-viewer tag. Upload your compressed GLB to the WordPress Media Library — it gives you a URL for the src attribute. One gotcha: WordPress blocks GLB uploads by default because it does not recognize the MIME type. You can add GLB support by putting this in your theme functions.php: function allow_glb($mimes) { $mimes["glb"] = "model/gltf-binary"; return $mimes; } add_filter("upload_mimes", "allow_glb");. Alternatively, upload the GLB to Cloudflare R2 (free egress) and use the external URL — this also offloads bandwidth from your WordPress host.
Can I add a 3D product viewer to my Shopify store?
Yes, and Shopify has native 3D support. Upload a compressed GLB directly in the product media section — Shopify uses Google Model Viewer internally, so the viewing experience is identical to self-hosting. Shopify handles CDN hosting, CORS headers, and mobile AR automatically. The limitation: you cannot customize the viewer appearance beyond Shopify built-in options. If you need custom camera angles, lighting, or branding around the viewer, self-host Model Viewer on a custom Liquid template page instead. For Shopify stores specifically, aim for GLB files under 4 MB — Shopify recommends this for optimal mobile performance across their themes.
How do I lazy-load the 3D model so it does not slow down my page?
Add loading="lazy" and a poster attribute to your model-viewer tag: <model-viewer src="model.glb" poster="preview.webp" loading="lazy" camera-controls></model-viewer>. The poster shows immediately (a static WebP image, ideally under 50 KB). The GLB only downloads when the element approaches the viewport. For pages with multiple 3D models (product galleries, portfolios), this is essential — without lazy loading, all models download simultaneously on page load, potentially fetching 20+ MB before the user sees anything. For even more control, use reveal="interaction" — the model loads only when the user clicks or taps the poster. In our tests, lazy loading plus a poster improved Largest Contentful Paint by 2.8 seconds on a page with three product models.

Related Tools

Related Format Guides