postMessage API
Use the loader unless you drive a hand-built
<iframe>. Its handle.on() and handle.set…()
methods build every message on this page for you.
The envelope
Every message, in either direction, is a plain object with channel: "cs2embed" and
a type. Both sides ignore any other message on the window, such as one from a
browser extension or an ad script.
Origin pinning
Both directions are pinned to an origin:
- Outbound (frame → host) messages go to the
originparameter on the embed URL, which the loader sets. Without it they go to your page'sdocument.referrer, and with neither to*. They carry the item's id, wear, seed and name tag, timings, load progress, refusal and fallback codes, and screenshot images. - Inbound (host → frame) messages are accepted only from
window.parent, at the exact origin resolved above. - The
originparameter must be a barehttporhttpsorigin of at most 255 characters. A trailing slash is trimmed. A value with a path, a query string or another scheme is ignored, and messages fall back to*.
Frame → host: events
Subscribe with handle.on(type, fn). Without the loader, listen for
message events on window.
| Type | Payload | When |
|---|---|---|
| ready | { backend } |
The frame has started and accepts commands. The loader queues anything you send earlier and sends it when this fires. |
| loaded | { id, name, ms, notes } |
The item is on screen. Usually this is the opening still
(first paint), about a second in, before the 3D view
has drawn. It also fires alongside a fallback, because the still stays
visible under the fallback's note. ms counts from the frame's start.
notes lists non-fatal decode notes and is usually empty. |
| interactive | { id, ms, notes } |
The 3D view has drawn its first frame. The visitor can now orbit, and
screenshot returns the live render. The loader queues commands sent before
this. notes is the complete list, including notes from applying the inspect
link's stickers and charm. Notes number sticker slots from 0, as st
does. |
| error | { code, message } |
An access refusal, such as an unknown key, an unregistered origin or a spent quota. Fires instead of loading the frame. See Error codes. |
| fallback | { code, message, id } |
An item problem after access was granted: missing WebGPU support, a bad inspect link, an item outside the catalog, or a load failure. The frame keeps its still and shows the reason in a note over it. A frame without a still shows a 2D card instead. See fallback codes. |
| progress | { value, label } |
Load progress, value from 0 to 1. |
| state | { id, wear, seed, nametag } |
The current item state, sent after each change, including changes 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. Takes the same fields and rules as the embed parameters. |
| setScene | { scene } | Change the backdrop. |
| setView | { view } | front | back |
top | hero. |
| setAutorotate | { on } | Turn autorotate on or off. |
| setQuality | { renderScale } | Set the 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. |
With the loader
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
With a raw iframe
var EMBED_ORIGIN = 'https://inspekt.gg';
var frame = document.querySelector('iframe.cs2-viewer');
// send commands once the frame is 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);
}
});
Add origin=https://yoursite.example to the iframe's src so the frame
addresses its messages to your page. See Embed parameters.