Docs

How to publish, share and embed a 3D model

Open a model, set it up once, publish a link and put it on your own site. Everything here is how the editor, the viewer and the API work today.

Last updated 16 October 2026

How do I start?

The editor runs in the browser. There is nothing to install, and the people you send a link to need no account.

  1. Open the editorapp.3dthing.in opens once you are signed in. No account yet? Create a free one, or ask for the demo account to look around first.
  2. Open a modelChoose Open model (Ctrl+O), or drag a GLB, glTF, FBX or OBJ onto the viewport. A .gltf that comes with a .bin and textures opens when you drop them together, or drop the whole folder. Draco, KTX2 and meshopt compressed files open directly.
  3. Keep it as a cloud projectNew project on the dashboard opens the editor in project mode. A strip above the editor shows the project name, whether it is saved, and a Save button. Changes are saved every minute while there are any, and straight away with Ctrl+S.
  4. Or send it from your 3D programInstall the plugin for Blender, 3ds Max or SketchUp, sign in with the code it shows, and press Send. The project appears on your dashboard with the program it came from and a report of how its materials were converted. The 3ds Max and SketchUp plugins are in preview.
  5. Publish a linkWhen it looks right, publish it and send the link. How publishing works is below.

Files it cannot open

3D Thing opens GLB, glTF, FBX and OBJ. It does not open .rvt, .skp, .3dm, .dwg, IFC, USDZ or STL files. Save the model out as one of the four first; the plugins page says how for Revit, Rhino, AutoCAD and Archicad.

Which keys does the editor use?

Single-key shortcuts can be changed in the Keys panel; Escape cancels a change. Copy, paste, undo and redo stay on their usual keys.

WERMove, rotate, resize handles
YPoint the handles along the world or along the item
=-Bigger or smaller handles
FFrame the selection, or the whole scene when nothing is selected
Shift+FFit the whole scene
137Front, right and top views (add Ctrl for back, left and bottom)
5Orthographic on or off
ZNext shading mode: shaded, wire, shaded with edges, clay, normals, UV
IIsolate the selection (hide everything else)
LLock or unlock the selection
GStart or stop walking
MMeasure
AAlign the selection to another object
CCamera switcher
Alt+WQuad view on or off
Shift+AAdd a box
DeleteDelete the selection
EscapeDeselect, or cancel a pick
Ctrl+KFind any command
Shift+?Help
Ctrl+SSave the project
Ctrl+OCtrl+EOpen a model, export as GLB
Ctrl+Shift+SScreenshot
Ctrl+CCtrl+VCtrl+DCopy, paste and duplicate an object, or just its material
Ctrl+ZCtrl+Shift+ZCtrl+YUndo, redo
Ctrl-clickShift-clickAdd to the selection, or toggle one item in it

How does publishing a link work?

Publishing turns the project, as it is at that moment, into a numbered version with its own link. Later edits do not change it.

  • Where: the Publish panel in the editor, or the project page.
  • Plain link: https://app.3dthing.in/?share=<id>. Add &v=<n> to name a version.
  • Pretty link: https://3dthing.in/s/<project-slug>-<projectId>/<version>, a page on this site with a preview picture for chat apps and the viewer filling the window.
  • What is kept: camera, lighting, environment, shadows, background, grid, effects, shading, the starting view, the logo, the plan map and the automatic tour settings. What you see while editing is what the viewer shows.
  • A smaller copy for the link: publishing compresses the copy the link serves, on your own machine, without moving a corner or renaming a part. The default keeps textures at full size; Ready for a phone and As small as it goes shrink them too.
  • Older versions: an older link keeps working until you unpublish it, its end date passes, or it falls outside the number of versions the account keeps. A version somebody opened in the last 90 days is always kept.
  • Unpublish from the project page removes the link and its stored model at once.
  • Branding: links carry a small 3D Thing badge. Where the account includes it, a link can carry your own logo instead.

Each publish makes a new link. A link you already sent keeps showing the version it was made for, so send the new link when you want people to see the new version.

Who can open a link, and for how long?

Anyone who has the link, unless you say otherwise. Each link has an access level, and can have a password and an end date.

Access levelView only, configure (change the options), or configure and comment (leave notes on the model).
End dateAfter it, the link says it has expired instead of showing the model.
PasswordAsked for once, when the link is opened.
More linksUp to ten links per version, each with its own label, access level, password and end date. A client link that can only look sits beside a team link that can comment.

What happens to a password

The viewer sends the password once, in the body of one request, and gets back a pass that opens that one link for 15 minutes. After that the pass travels with each request in a header, not the password. The password never appears in an address, so it never ends up in a server log. Change the password and every pass made for the old one stops working at once.

What the people you send it to need

Nothing: no account and no install. When a visitor leaves a note or saves a design, their browser makes up a random id of its own, and that id is what makes those notes theirs. They see and can delete their own notes and designs, and nobody else's. Like the pass, it travels in a header, never in an address. The API reference has the exact requests.

How do I put a model on my own site?

An embed is the viewer without the editor around it. Paste the snippet from the project page, or write it yourself with the link's id:

HTML
<iframe
  src="https://app.3dthing.in/?share=SHARE_ID&embed=1"
  title="My product in 3D"
  width="100%" height="600"
  style="border:0;border-radius:12px"
  allow="fullscreen; xr-spatial-tracking"
  allowfullscreen loading="lazy">
</iframe>

A plain embed shows the model and sends nothing to your page. Measuring stays in the full viewer; it is not part of the embed. When the model has a configurator, the embed can tell your page what a visitor picks, which is the next section.

How does my page hear what visitors choose?

A configurator in an embed talks to the page around it with postMessage. Nothing that identifies the visitor is sent.

Every message carries source: '3dt', the protocol version (1 today) and the visitor's current choice: code (the value that reproduces it in a link), lines (one { group, choice, price } per option group), total, currency and url (a link that opens the configurator on that choice).

Example: a change message
{
  source: '3dt', version: 1, type: 'change',
  code: 'a1.b3',
  lines: [{ group: 'Fabric', choice: 'Olive boucle', price: 120 }],
  total: 1570, currency: 'USD',
  url: 'https://app.3dthing.in/?share=SHARE_ID&config=a1.b3'
}
readyThe configurator has loaded. Also carries groups: the option groups a visitor can change, each with an id, a label and a kind.
changeThe visitor changed a choice. Sent once the choice settles, so dragging a slider is one message, not a flood.
quoteThe visitor pressed the button you added in the configurator, such as Request a quote or Add to cart. Your page answers with ack.
stateThe answer to a getState from your page.

Messages go only to the page that framed the configurator, at the address the browser gives for it, and the configurator listens only to that page. On a browser that will not say which site framed it, your page can still ask for the current choice but cannot change it. To listen, paste this into your page and put your own logic where the comments are:

HTML
<script>
window.addEventListener('message', function (e) {
  if (e.origin !== 'https://app.3dthing.in') return;      // only the configurator
  var m = e.data;
  if (!m || m.source !== '3dt') return;
  if (m.type === 'change') {
    // m.lines is [{ group, choice, price }], m.total and m.currency say what it comes to, m.code reproduces it
  }
  if (m.type === 'quote') {
    // add m.lines and m.total to your cart or enquiry form, then tell the window it worked:
    e.source.postMessage({ source: '3dt', type: 'ack', ok: true, message: 'Added to your enquiry' }, e.origin);
  }
});
</script>
getStateAsks for the current choice. The answer is a state message.
setConfigWith a code: switches the configurator to that choice. Codes use letters, digits and _ . ~ -, up to 600 characters.
resetBack to the starting choice.
ackYour answer to a quote: ok and a short message (up to 200 characters) shown to the visitor. With no answer within 1.5 seconds, the configurator tells the visitor it was not heard.
JavaScript
// From your page to the configurator in the frame
const frame = document.querySelector('iframe');
const to = 'https://app.3dthing.in';
frame.contentWindow.postMessage({ source: '3dt', type: 'getState' }, to);
frame.contentWindow.postMessage({ source: '3dt', type: 'setConfig', code: 'CODE_FROM_A_LINK' }, to);
frame.contentWindow.postMessage({ source: '3dt', type: 'reset' }, to);

Anything else, or a malformed message, is ignored.

How do scripts and plugins sign in?

With a personal access token. Create one on the API tokens page, pick what it may do and when it expires, and copy it: the full value is shown once and only a fingerprint of it is stored. The plugins make their own through the code you approve on this site, named after the program and the computer.

Shell
curl https://3dthing.in/api/bridge/me \
  -H "Authorization: Bearer 3dt_pat_XXXXXXXX"

Send Authorization: Bearer <token> on any /api/* request. Revoking a token on the account page stops it at once. Scopes, endpoints, uploads and webhooks are in the API reference.