Player Events
Using postMessage events from the KissKH player for progress tracking, auto-next, and watch history
Updated May 5, 2026
OtakuThemes Team
Overview
The KissKH player sends postMessage events to the parent window during playback. You can listen for these events on your page to build features like auto-next episode, watch progress tracking, and watch history.
KissKH Player Docs
Event Structure
Events are sent as JSON objects. There are two formats:
KissKH Channel Events
{
"channel": "kisskh",
"event": "time",
"currentTime": 42.5,
"duration": 1440.0
}| Field | Description |
|---|---|
channel | Always "kisskh" |
event | Event name — see table below |
currentTime | Current playback position in seconds |
duration | Total episode duration in seconds |
Watching Log Events
{
"type": "watching-log",
"currentTime": 42.5,
"duration": 1440.0
}Event Reference
| Event | Format | When fired |
|---|---|---|
time | { channel: "kisskh", event: "time", currentTime, duration } | Continuously during playback (every few seconds) |
complete | { channel: "kisskh", event: "complete" } | When the episode finishes playing |
error | { channel: "kisskh", event: "error", message } | When playback fails or a stream error occurs |
watching-log | { type: "watching-log", currentTime, duration } | Periodic watch-time log during playback |
Listening for Events
Add a message event listener on window in your parent page:
window.addEventListener("message", function (event) {
let data = event.data;
// Some browsers may send the data as a JSON string
if (typeof data === "string") {
try { data = JSON.parse(data); } catch (e) { return; }
}
// KissKH channel events
if (data.channel === "kisskh") {
if (data.event === "complete") {
// Episode finished — load the next episode
loadNextEpisode();
}
if (data.event === "time") {
// Save watch progress
saveProgress(data.currentTime, data.duration);
}
if (data.event === "error") {
// Handle playback error
console.error("Player error:", data.message);
}
}
// Watching log (alternative progress format)
if (data.type === "watching-log") {
saveProgress(data.currentTime, data.duration);
}
});Auto-Next Episode Example
window.addEventListener("message", function (event) {
let data = event.data;
if (typeof data === "string") {
try { data = JSON.parse(data); } catch (e) { return; }
}
if (data.channel === "kisskh" && data.event === "complete") {
const iframe = document.getElementById("player-iframe");
if (iframe && nextEpisodeId) {
iframe.src = "https://your-server.com/kisskh/" + nextEpisodeId;
}
}
});Watch Progress Example
let lastSaved = 0;
window.addEventListener("message", function (event) {
let data = event.data;
if (typeof data === "string") {
try { data = JSON.parse(data); } catch (e) { return; }
}
if (data.channel === "kisskh" && data.event === "time") {
// Save every 10 seconds to avoid excessive writes
if (data.currentTime - lastSaved > 10) {
lastSaved = data.currentTime;
localStorage.setItem("progress-" + episodeId, data.currentTime);
}
}
});Security Note
Always validate event.origin in production if your server is restricted to specific domains:
window.addEventListener("message", function (event) {
if (event.origin !== "https://your-server.com") return;
// ... handle event
});