Viewer Embed
/
Plain Iframe
Viewer Embed with a Plain Iframe
You don't have to ship the SDK. The viewer works as a regular iframe — useful when you can't add a third-party script, when you want full control over the DOM, or when CSP rules block external scripts.
URL pattern
Plain
https://moshpit.studio/viewer/embed/{publicKey}?session={sessionToken}&splatId={splatId}The iframe needs both the session query param and a valid splatId. Without a session it shows a "Viewer session is required" page.
Minimal example
You can't hard-code a session token in HTML — they expire in 15 minutes. Always fetch one from your backend first, then set the src:
HTML
<iframe
id="moshpit-viewer"
width="100%"
height="600"
style="border: 0"
allow="fullscreen; microphone"
allowfullscreen
loading="lazy"
referrerpolicy="strict-origin-when-cross-origin"
></iframe>
<script>
async function loadMoshpitViewer() {
const response = await fetch('/api/moshpit/viewer-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ splatId: 'YOUR_SPLAT_ID' }),
});
if (!response.ok) throw new Error('Unable to create viewer session');
const { sessionToken } = await response.json();
const url = new URL('https://moshpit.studio/viewer/embed/mpk_PUBLIC_KEY');
url.searchParams.set('session', sessionToken);
url.searchParams.set('splatId', 'YOUR_SPLAT_ID');
document.getElementById('moshpit-viewer').src = url.toString();
}
loadMoshpitViewer();
</script>The matching backend route lives in Quickstart.
Recommended iframe attributes
| Attribute | Value | Why |
|---|---|---|
allow | fullscreen | Allow the user to enter fullscreen mode |
allowfullscreen | (boolean) | Older browsers' fullscreen flag |
loading | lazy | Let the browser defer loading until the iframe is near the viewport |
referrerpolicy | strict-origin-when-cross-origin | Don't leak the host page's full URL |
width="100%" and a fixed height on the iframe is the simplest layout. For responsive embeds, wrap the iframe in a 16:9 aspect-ratio container.
This iframe attribute controls the request from your page to the Viewer Embed.
The hosted viewer separately uses Referrer-Policy: no-referrer for its own
Scene-file and API requests.
Listening for events without the SDK
The iframe sends events to its immediate parent via postMessage. Listen for them on window:
JavaScript
const iframe = document.getElementById('moshpit-viewer');
window.addEventListener('message', (event) => {
if (event.origin !== 'https://moshpit.studio') return;
if (event.source !== iframe.contentWindow) return;
const data = event.data;
if (data?.source !== 'moshpit-viewer') return;
switch (data.type) {
case 'ready':
console.log('viewer ready');
break;
case 'viewTracked':
console.log('view tracked', data.payload);
break;
case 'sessionExpiring':
// Refresh the session — see Session Tokens
break;
}
});The full event catalog is at Viewer Events.
Sending commands without the SDK
Send commands the same way the SDK does — a postMessage with the moshpit-sdk source:
JavaScript
const iframe = document.getElementById('moshpit-viewer');
iframe.contentWindow.postMessage(
{
source: 'moshpit-sdk',
type: 'command',
target: 'viewer',
command: 'setQuality',
value: 'high',
},
'https://moshpit.studio',
);Always pass the explicit target origin ('https://moshpit.studio') — never '*' — so messages can't be intercepted by other frames.
The full command catalog is at Viewer Commands.
Manual session refresh
Plain iframes don't auto-refresh sessions. Either:
- Listen for the
sessionExpiringevent and call your session endpoint, then send anupdateSessioncommand back into the iframe. - Set a timer slightly before the token's
expiresAtand refresh proactively.
Both patterns are spelled out in Session Tokens → Refresh before expiry.
What's next
- Viewer Commands — every postMessage command.
- Viewer Events — every postMessage event.
- Viewer → With the SDK — same flow without the manual wiring.