I’m trying to track watch time of a video with using JavaScript. But the problem is sometimes the script works well and sometimes it doesn’t. I want to show a Next video
button when the video is 90% watched by user, in ideal scenario the button shows up button sometimes it just doesn’t, How can I fix this issue ?
this is my html
, I’m using bootstrap CDN along with html
:
<head>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<div class="cursor-pointer pt-4 d-flex justify-content-center align-items-center flex-column">
<video class="w-50" poster="" id="plyr-video-player" playsinline controls>
<source src="https://therapywebsite.s3.amazonaws.com/Binaural+Beats+Fast+5+min+meditation+Stress+Relief+%5Bxc3MacYfdbI%5D.mp4" type="video/mp4" />
</video>
</div>
<div class="pt-4 d-flex justify-content-center align-items-center flex-column">
<h5>Welcome to this session</h5>
<button class=" d-none w-25 btn btn-primary me-3" id="next-video-btn">Next video</button>
</div>
</body>
& this is my script:
<script>
document.addEventListener("DOMContentLoaded", (event) => {
const video = document.getElementById("plyr-video-player");
const nextVideoBtn = document.getElementById("next-video-btn");
const videoId = 1;
const postInterval = 10;
let playedCount = 0;
let lastPlayedTime = 0;
let totalWatchedTime = 0;
let actualWatchedTime = 0;
let isTabActive = true;
let skipDetected = false;
let isVideoVisible = true;
document.addEventListener("visibilitychange", () => {
isTabActive = !document.hidden;
});
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
isVideoVisible = entry.isIntersecting;
});
}, {threshold: 0.5});
observer.observe(video);
video.addEventListener("loadedmetadata", () => {
const videoDuration = Math.floor(video.duration);
const playedCountThreshold = Math.floor(videoDuration * 0.9);
if (videoDuration){
console.log("Metadata loaded")
} else{
console.log("Metadata isn't loaded yet!!")
}
const showVideoBtn = () =>{
if (video.currentTime > playedCountThreshold) {
if (nextVideoBtn.classList.contains("d-none")) {
nextVideoBtn.classList.remove("d-none");
}
}
};
function autoPlay() {
return video.play();
}
autoPlay().catch(error => {
console.error("Autoplay failed:", error);
});
setTimeout(autoPlay, 1000)
function trackVideo(eventType, currentTime){
currentTime = Math.floor(currentTime);
if (isTabActive && isVideoVisible){
if (currentTime > playedCountThreshold && lastPlayedTime <= playedCountThreshold) {
playedCount++;
}
if (eventType !== "play" || eventType === "timeupdate"){
const timeDiff = Math.max(0, currentTime - lastPlayedTime);
actualWatchedTime += timeDiff;
} else if (eventType === "seeked") {
skipDetected = true;
const skippedTime = Math.max(0, currentTime - lastPlayedTime);
actualWatchedTime -= skippedTime;
}
totalWatchedTime = actualWatchedTime;
fetch("/track_video/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": "{{ csrf_token }}"
},
body: JSON.stringify({
video_id: videoId,
played_count: playedCount,
video_duration: videoDuration,
last_played_time: lastPlayedTime,
total_watched_time: totalWatchedTime,
})
});
}
lastPlayedTime = currentTime;
}
video.addEventListener("play", () => trackVideo('play', video.currentTime));
video.addEventListener("pause", () => trackVideo("pause", video.currentTime));
video.addEventListener('timeupdate', () => {
if (video.currentTime - lastPlayedTime >= postInterval) {
trackVideo('timeupdate', video.currentTime);
}
showVideoBtn();
});
video.addEventListener("seeked", () =>{
skipDetected = true;
lastPlayedTime = Math.floor(video.currentTime)
trackVideo("seeked", video.currentTime)
});
});
nextVideoBtn.addEventListener("click", () => {
window.location.href = "/next_video.html";
});
});
</script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>