How Do Sketchfab and Meshy Protect Their 3D Models From Being Downloaded?
If you've ever opened DevTools on a Three.js site, you already know the drill: hit the Network tab, filter for XHR or Fetch, and there it is a .glb or .gltf file sitting in the requests. Download it, open it in Blender, and you've got the original model.
Try that on Sketchfab or Meshy and you won't have the same luck. Instead of a plain .glb, you'll see odd, unfamiliar files things like .binz or .meshy. So what's actually going on?
It's not the file extension
The first thing to get out of the way: the weird extension itself isn't what's protecting anything. Renaming a file, obfuscating a filename, disabling right-click, hiding a download button none of that stops someone who actually knows what they're doing. If the browser can render the model, the browser has the data, and that data can be captured.
What Sketchfab and Meshy are actually doing is more fundamental: they never let the browser receive a plain, reusable .glb in the first place.
Why a normal Three.js setup can't hide anything
A standard delivery pipeline looks like this:
Your Server → model.glb → Browser → GLTFLoader → WebGL
The browser needs the model in a form Three.js can parse and hand to the GPU. That means it's sitting in the Network tab in a usable state, full stop. HTTPS doesn't change this — it protects the data in transit, not after the browser has already unpacked it. Neither does CORS, an auth token on the request, or any of the usual deterrents. They're fine as a mild speed bump, but the file is still there.
So what are they actually doing differently?
Platforms built for this problem introduce a processing or encryption layer between the stored model and the renderer, instead of exposing the source file directly:
Original Model → Encryption/Processing → Protected Payload → Browser → Custom Loader → WebGL
The browser still ends up receiving something it has to, in order to render anything but that something is an encrypted or transformed payload, not a usable .glb. A custom runtime on the client side decodes it just before rendering, and the plaintext model never exists as a downloadable file at any point.
This is also why people assume these platforms run some kind of "custom WebGL." They don't WebGL is a standard browser API, and there's no secret proprietary replacement for it. What's actually custom is everything around WebGL: the asset format, the loader, the decryption step, the licensing checks. Controlling that whole chain end-to-end is what makes casual extraction difficult, not any single trick.
Can a 3D model ever be fully unextractable?
No, and it's worth being honest about that. At some point the browser needs enough information to render the model that's just how rendering works. A sufficiently determined attacker with enough time can eventually get at anything the client renders. So the realistic goal isn't making extraction impossible. It's making the lazy, one-click version of it open Network tab, grab .glb, done stop working. That alone filters out the overwhelming majority of people who'd otherwise just take your asset.
A Free, Easy Way to Get This Same Protection: Secure3JS
Building this kind of pipeline from scratch encryption, a custom loader, runtime decryption, licensing checks is a real engineering project. Most people showcasing 3D work don't have the time or need for a full in-house DRM system. That's the gap Secure3JS fills, and it's free to use.
Instead of serving your .glb directly, Secure3JS encrypts it with AES-256 before it's ever hosted. The pipeline looks like this:
model.glb → AES-256 Encryption → Encrypted Asset → CDN → Secure3JS Runtime → Decryption in memory → Three.js / WebGL
The decryption happens in memory, at runtime, using the Web Crypto API, through a custom SecureGLTFLoader. The plaintext model is never written to disk and never sent to the browser as a standalone file so instead of your Network tab showing my-secret-model.glb, it just shows an opaque encrypted blob. There's also optional domain whitelisting and session-based credentials on top, so even the decryption step only works where you've explicitly allowed it.
It's not a full custom rendering pipeline the way Sketchfab or Meshy have built internally but it gets you a meaningful layer of the same protection, without having to build any of it yourself, and it drops into an existing Three.js project without a rewrite.
Where this actually matters
If you're showing off product configurators, furniture, jewelry, automotive or architectural work, game characters, CAD models, or any asset you don't want people walking away with for free, this is the difference between "hide the URL" and "actually change how the model reaches the browser." The first one is theater. The second one is real protection.
This is the first in a short series on 3D asset protection. Coming up: how attackers actually extract .glb files from Three.js sites, why HTTPS/CORS/JWTs don't solve this on their own, how runtime decryption works under the hood, and a hands-on guide to encrypting your first model with Secure3JS.