You’ve exported a 3D Tiles dataset from Pix4D, Metashape, RealityCapture, or Cesium ion. Now you want to send it to a client. The first thing you notice: it’s not a file. It’s a directory.
A 3D Tiles dataset is a tileset.json root manifest plus a tree of tile files — typically a few hundred to several hundred thousand individual .b3dm, .pnts, .glb, or .i3dm files spread across nested subfolders. Total count for a typical drone survey: 5,000 – 50,000 files. For a city-scale LiDAR capture: millions.
You can’t email a folder of 50,000 files. You can’t WeTransfer it either (well, you can — but the client downloads a zip with 50,000 useless files inside). 3D Tiles is built to be served over HTTP, streamed tile by tile. So the question isn’t how to send it. It’s where to host it.
Here are the actual options.
Option 1: AWS S3 + CloudFront
The most common self-hosted setup. Upload the entire 3D Tiles folder to an S3 bucket, sit a CloudFront distribution in front for HTTPS and edge caching, point your CesiumJS viewer at the tileset URL.
The setup, roughly:
- Create an S3 bucket. Block public access off (or use signed URLs — more on that below).
aws s3 sync ./tileset/ s3://your-bucket/dataset-name/ --acl public-read- Configure CORS on the bucket so browsers can fetch tiles from another origin (more on this below).
- Create a CloudFront distribution pointing at the bucket. Enable HTTPS.
- Build or deploy a CesiumJS viewer page that loads
https://your-cdn.cloudfront.net/dataset-name/tileset.json. - Send the viewer URL to the client.
Pros: Cheap. S3 storage is roughly $0.023/GB/month; CloudFront egress is around $0.085/GB but heavily cached. You own the data and the URL.
Cons: Every step assumes you can configure CORS, IAM policies, CloudFront origins, and host a CesiumJS viewer somewhere. There’s no UI. Every new client delivery is a fresh deploy. No access control unless you build it.
Cost estimate: $5 – $50/month for a small surveying business hosting a handful of active datasets.
Option 2: Your own server / VPS
A $10/month VPS with nginx is enough to serve 3D Tiles. Drop the tileset folder into /var/www/html/tileset/, configure nginx with the right MIME types and CORS headers, point your viewer at the URL.
location /tileset/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, HEAD";
types {
application/json json;
application/octet-stream b3dm pnts i3dm cmpt glb;
}
}
Pros: Cheapest possible setup. Full control.
Cons: Single region, no edge caching, no scale. Bandwidth costs are linear with traffic. Storage limited to the VPS disk. If the VPS dies, the link dies.
Best for technically capable teams hosting one or two datasets for in-house review, not for client delivery at scale.
Option 3: GitHub Pages / Cloudflare Pages / Netlify
It works — to a point. GitHub Pages, Cloudflare Pages, and Netlify can all host static files including 3D Tiles. Push the tileset folder to a Git repo, the platform serves it over HTTPS with CORS enabled by default.
The catch: file count and repo size limits. GitHub Pages caps at 1 GB per repo and recommends < 100 MB per file. A typical drone survey 3D Tiles export blows through this immediately. Cloudflare Pages limits at 20,000 files per deployment. Netlify caps at 8 MB per individual file but no total cap.
For small tilesets (a few hundred megabytes, < 10,000 files) this can work. For anything bigger, you’re back to S3.
Option 4: Cesium ion
Cesium’s managed platform — the team behind 3D Tiles itself. Upload your point cloud, mesh, or pre-tiled dataset, Cesium handles conversion and hosting, you get a tileset asset ID and an embeddable viewer.
Pros: Built by the people who designed 3D Tiles. Excellent performance. Handles conversion from raw point clouds, photogrammetry meshes, and CAD. Provides a developer SDK.
Cons: Pricing is tiered by storage and bandwidth — $25/month gets you 5 GB; $500/month gets you the Professional tier with more storage. Egress overages get expensive fast on large datasets. The viewer is developer-oriented — branding, custom UI, client access control all require front-end engineering. Not designed as a turnkey client delivery tool.
Best for developers building 3D Tiles into a larger application, or enterprise teams with dedicated engineering.
CORS, HTTPS, and range requests — the three hosting requirements
Whatever path you pick, the host needs to satisfy three things or browsers will refuse to render the tileset:
HTTPS. CesiumJS will not load tiles from an HTTP origin if the viewer page itself is HTTPS (mixed content). Any modern hosting handles this — but a bare VPS needs Let’s Encrypt or equivalent.
CORS headers. The tileset is fetched by JavaScript from a different origin than the viewer page. The tile origin must respond with Access-Control-Allow-Origin: * (or the specific viewer domain). Missing CORS is the single most common reason a 3D Tiles deployment fails — the tileset.json loads, then every tile request fails silently.
Range requests. Some 3D Tiles content (particularly external glTF tiles) uses HTTP byte-range requests to fetch only part of a binary file. The host must respond to Range: headers with 206 Partial Content. S3, CloudFront, and most modern static hosts do this by default. Older nginx configs sometimes don’t.
If your viewer shows a black scene with no errors in the console, check CORS first. If tiles load but render incorrectly, check that range requests are supported.
Authentication — the hard problem
You hosted the tileset. The URL works. Anyone with the URL can now view your client’s data. How do you restrict access to just the people you’ve shared with?
This is where DIY hosting falls apart for client delivery. The options:
Signed URLs. CloudFront and S3 support signed URLs that expire after a window. The problem: 3D Tiles has hundreds or thousands of tile URLs. You can sign the tileset.json, but the tiles it references are fetched separately. You’d need to sign every tile URL — or use signed cookies, which CloudFront supports but require configuring your viewer to send credentials.
IP allowlisting. Works for a known recipient on a fixed network. Useless for typical clients on home internet or mobile.
Token in URL. Pass a token as a query string, validate at the edge via Lambda@Edge or a Cloudflare Worker. Implementable but requires engineering.
Password-protected viewer page. Easiest. Put the auth at the viewer layer, not the tileset layer. The tileset URL itself is technically public (or behind signed cookies), but the viewer page requires a password before it loads.
Most self-hosted surveying deployments end up at “tileset is public, viewer page requires a password and we don’t publish the tileset URL anywhere.” That’s adequate for most client delivery and miles less hassle than tile-level signed URLs.
What the recipient sees
A well-configured 3D Tiles share is a URL like:
https://hub.example.com/share/quarry-2026-05
The recipient clicks. A viewer page loads — your CesiumJS implementation, or whatever viewer you’ve built. The tileset streams in over the next few seconds, starting from the lowest LOD and progressively refining as the camera settles. They can rotate, pan, zoom, measure. No software install. No download.
If you’ve built it well, there’s no indication that they’re looking at 50,000 individual files. It just feels like a 3D model that loads instantly. That’s the whole point of the format.
If you’ve built it badly: a blank scene, a “failed to load tileset” error, or 30 seconds of black before anything appears. Usually a CORS or HTTPS issue. See above.
Sharing the link in practice
The mechanics that actually matter to clients:
- Permanent URL. Not a download link that expires in 7 days. The link should still work in two years.
- Mobile compatible. Cesium runs on mobile browsers. The viewer should be responsive.
- No login required (or one-click login). Friction kills engagement. If the client has to create an account to view your survey, they won’t.
- Branded. Your colours, your logo, your domain. Cesium ion’s default viewer is unbranded — that’s fine for prototyping, not for billable deliverables.
- Bookmarkable views. Clients want to share a specific angle or location with colleagues. Camera state in the URL hash is a 30-line CesiumJS feature; most DIY viewers don’t bother.
These aren’t technical 3D Tiles problems. They’re delivery experience problems. Solving them is what separates a working URL from a professional deliverable. Worth reading: how to deliver drone survey data.
Branded delivery via Swyvl
Swyvl is the managed alternative. Upload a 3D Tiles dataset (or the source — point cloud, photogrammetry mesh, GLB) and Swyvl handles the hosting, the CesiumJS viewer, CORS, HTTPS, range requests, and access control. You get a branded share link on your own subdomain that opens to your colours and logo, with no infrastructure to configure. Recipients get a permanent URL, no login required by default, with optional password protection if you need it.
The technology to share 3D Tiles is solved. The hard part is the surrounding work — hosting that doesn’t fall over, CORS that works, access control that’s reasonable, branding that looks professional, and a URL that doesn’t expire. If you only ship one tileset a year, self-host on S3. If you ship every week, the time you save not configuring CORS pays for a managed platform several times over.