Inspekt
Get a key

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:

Frame → host: events

Subscribe with handle.on(type, fn), or listen for message yourself if you're not using the loader.

TypePayloadWhen
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.

TypePayloadEffect
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)

javascript
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

javascript
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 *.