Skip to workspace
Developer kit Events & progress
Open playground
INTEGRATION REFERENCE

Events & progress

Keep your application in the loop.

04

Playback happens in the iframe. Your application receives structured messages through window.postMessage.

Your application
INIT / READY↔
Player iframe

Connect once, listen safely

The existing VELARIUM_EMBED_INIT and VELARIUM_EMBED_READY handshake names remain stable for compatibility. Ready messages contain no playback data; sending INIT lets the player verify its parent before sharing progress.

PARENT WINDOW · JAVASCRIPT
// Run after the iframe is mounted.
const frame = document.getElementById("velarium-player");
const playerOrigin = "https://velarium.cc";

function connect() {
  frame.contentWindow?.postMessage(
    { type: "VELARIUM_EMBED_INIT" }, playerOrigin
  );
}

function onMessage(message) {
  if (message.origin !== playerOrigin) return;
  if (message.source !== frame.contentWindow) return;
  const payload = message.data;
  if (!payload || typeof payload !== "object") return;

  if (payload.type === "VELARIUM_EMBED_READY") connect();

  if (payload.type === "PLAYER_EVENT") {
    const data = payload.data;
    if (!data || typeof data.event !== "string" ||
        !Number.isFinite(data.currentTime) ||
        !Number.isFinite(data.duration)) return;
    console.log(data.event, data.currentTime, data.duration);
  }

  if (payload.type === "MEDIA_DATA" && payload.data &&
      typeof payload.data === "object") {
    // Storage can be unavailable in privacy mode.
    try {
      localStorage.setItem("velarium-progress",
        JSON.stringify(payload.data));
    } catch { /* Keep playback working without storage. */ }
  }
}

window.addEventListener("message", onMessage);
frame.addEventListener("load", connect);
connect();

// On unmount:
// window.removeEventListener("message", onMessage);
// frame.removeEventListener("load", connect);

PLAYER_EVENT

Each message describes playback at the time it was emitted. Subscribe to the events your application needs.

playpauseseekedendedtimeupdate
EXAMPLE PAYLOAD · TV
{
  "type": "PLAYER_EVENT",
  "data": {
    "event": "pause",
    "currentTime": 93.4,
    "duration": 2680,
    "tmdbId": 94997,
    "mediaType": "tv",
    "season": 1,
    "episode": 1
  }
}

season and episode apply to TV. Use the resolved tmdbId even when the original URL uses an IMDb ID.

MEDIA_DATA

A progress snapshot keyed by TMDB ID. watched and duration use seconds; last_updated uses Unix milliseconds. TV records also include per-episode progress.

EXAMPLE PROGRESS SNAPSHOT
{
  "type": "MEDIA_DATA",
  "data": {
    "94997": {
      "id": 94997,
      "type": "tv",
      "title": "Example series",
      "poster_path": "/poster.jpg",
      "backdrop_path": "/backdrop.jpg",
      "progress": {
        "watched": 93.4,
        "duration": 2680
      },
      "last_season_watched": 1,
      "last_episode_watched": 1,
      "show_progress": {
        "s1e1": {
          "progress": {
            "watched": 93.4,
            "duration": 2680
          }
        }
      },
      "last_updated": 1789257600000
    }
  }
}
Save progress locally or in your own backend. Local storage is device-specific and may be blocked. Throttle frequent updates before writing to a server, validate incoming data, and never trust messages from unrelated windows.