postMessage API
The channel between your page and the embedded frame. If you use the
CS2Embed.mount() loader, you never build these messages by hand: handle.on()
and the handle.set…() methods wrap this exactly. This page is for when you're
driving a hand-built <iframe> yourself, or want to know what's actually crossing
the boundary.
The envelope
Every message, either direction, is a plain object with channel: "cs2embed" plus a
type. Anything else on window's message bus (a browser extension, an ad
script, an unrelated widget) is ignored by both sides because it won't carry that shape.
Origin pinning
Both directions are pinned to an origin, not left open:
- Outbound (frame → host) is addressed to the
originparam you (or the loader) set on the embed URL. With none, it falls back to your page'sdocument.referrer. With neither of those, it's addressed to*, which is safe because these messages never carry anything sensitive: ids, timings, progress, a small image blob. - Inbound (host → frame) is accepted only from
window.parentitself, and only from the exact origin the frame resolved above, when one was resolvable.
Frame → host: events
Subscribe with handle.on(type, fn), or listen for message yourself if
you're not using the loader.
| Type | Payload | When |
|---|---|---|
| ready | { backend } |
The frame has initialized and will accept commands. Anything you send before this fires is queued by the loader and flushed once it does. |
| loaded | { id, name, ms, notes } |
The item finished loading and is on screen. ms is load time;
notes is a (usually empty) list of non-fatal decode notes. |
| error | { code, message } |
An access refusal: a bad or unregistered key, wrong origin, or an over-quota key. Fired instead of the frame loading at all. See Error codes. |
| fallback | { code, message, id } |
An item problem after access was granted: no WebGPU, a bad inspect link, an item not yet in the catalog, or a load failure. The frame shows a 2D fallback card instead of the 3D view. See fallback codes. |
| progress | { value, label } |
Load progress, value from 0 to 1. |
| state | { id, wear, seed, nametag } |
The current item state, emitted after it changes (including from your own
setItem commands). |
| screenshot | { requestId, blob, error? } |
The answer to a screenshot command, matched by requestId.
blob is null and error is set on failure. The loader
turns this into the Promise that handle.screenshot() returns. |
Host → frame: commands
Send with the matching handle.set…() / handle.resetView() /
handle.screenshot() method, or post the object yourself.
| Type | Payload | Effect |
|---|---|---|
| setItem | { inspect?, s?, wear?, seed?, st?, name? } |
Swap the item without remounting the frame. Same fields and rules as the boot params. |
| setScene | { scene } | Change the backdrop. |
| setView | { view } | front | back |
hero. |
| setAutorotate | { on } | Enable/disable the turntable. |
| setQuality | { renderScale } | Adjust internal render resolution. |
| resetView | {} | Return the camera to its default framing. |
| screenshot | { requestId, width?, height?, format?, quality? } |
Capture the current frame as a blob, answered by a screenshot event with the
same requestId. |
Using the loader (recommended)
var viewer = CS2Embed.mount(el, { inspect: inspectLink });
viewer.on('loaded', function (e) { console.log(e.id, e.ms + ' ms'); });
viewer.on('error', function (e) { console.error('access refused:', e.code, e.message); });
viewer.on('fallback', function (e) { console.warn('showing fallback:', e.code); });
viewer.setView('back');
viewer.setAutorotate(false);
viewer.screenshot({ width: 1200, height: 630, format: 'image/webp', quality: 0.9 })
.then(function (blob) { /* a Blob, ready to upload or download */ })
.catch(function (err) { console.error(err); });
viewer.destroy(); // unmounts the iframe and drops all pending listeners
Driving a raw iframe by hand
var EMBED_ORIGIN = 'https://inspekt.gg';
var frame = document.querySelector('iframe.cs2-viewer');
// send a command once the frame signals it's ready
window.addEventListener('message', function (e) {
if (e.origin !== EMBED_ORIGIN) return;
var d = e.data;
if (!d || d.channel !== 'cs2embed') return;
if (d.type === 'ready') {
frame.contentWindow.postMessage(
{ channel: 'cs2embed', type: 'setView', view: 'back' },
EMBED_ORIGIN
);
}
if (d.type === 'error') {
console.error('embed refused:', d.code, d.message);
}
});
Remember to set ?origin=https://yoursite.example on the iframe's src (see
Embed parameters) so the frame addresses its messages to your page
specifically rather than falling back to the referrer or *.