Does anyone knows how I can check if a video was completely watched or not? I am using html5 video players:
<video width="480" height="400" controls="true" poster="">
<source type="video/mp4" src="video.mp4"></source>
</video>
Basic check is simple, wait for the ended
event. This is so simple you can just google it.
Now to check that user played full video an extensive analysis would be needed checking if he played every second of it. That's not necessary however, it should be enough that user:
This snippet demonstrates exactly that. The video will not be marked as fully played if you just skip to the end. Playing the beginning over and over will also not mark it fully played:
var video = document.getElementById("video");
var timeStarted = -1;
var timePlayed = 0;
var duration = 0;
// If video metadata is laoded get duration
if(video.readyState > 0)
getDuration.call(video);
//If metadata not loaded, use event to get it
else
{
video.addEventListener('loadedmetadata', getDuration);
}
// remember time user started the video
function videoStartedPlaying() {
timeStarted = new Date().getTime()/1000;
}
function videoStoppedPlaying(event) {
// Start time less then zero means stop event was fired vidout start event
if(timeStarted>0) {
var playedFor = new Date().getTime()/1000 - timeStarted;
timeStarted = -1;
// add the new number of seconds played
timePlayed+=playedFor;
}
document.getElementById("played").innerHTML = Math.round(timePlayed)+"";
// Count as complete only if end of video was reached
if(timePlayed>=duration && event.type=="ended") {
document.getElementById("status").className="complete";
}
}
function getDuration() {
duration = video.duration;
document.getElementById("duration").appendChild(new Text(Math.round(duration)+""));
console.log("Duration: ", duration);
}
video.addEventListener("play", videoStartedPlaying);
video.addEventListener("playing", videoStartedPlaying);
video.addEventListener("ended", videoStoppedPlaying);
video.addEventListener("pause", videoStoppedPlaying);
#status span.status {
display: none;
font-weight: bold;
}
span.status.complete {
color: green;
}
span.status.incomplete {
color: red;
}
#status.complete span.status.complete {
display: inline;
}
#status.incomplete span.status.incomplete {
display: inline;
}
<video width="200" controls="true" poster="" id="video">
<source type="video/mp4" src="http://www.w3schools.com/html/mov_bbb.mp4"></source>
</video>
<div id="status" class="incomplete">
<span>Play status: </span>
<span class="status complete">COMPLETE</span>
<span class="status incomplete">INCOMPLETE</span>
<br />
</div>
<div>
<span id="played">0</span> seconds out of
<span id="duration"></span> seconds. (only updates when the video pauses)
</div>
You can then connect this to google analytics to see how many of the video users played. Simple code from google analytics website:
ga('send', 'event', 'Videos', 'play', 'Video name');
seeking
option? so no one can seek forward.
Math.round(timePlayed)+"";
rounds to nearest whole number (up or down).... change this to Math.ceil(timePlayed)+"";
and it will only round up to solve this bug.
round
to ceil
here changes nothing.
Commented
Jan 16, 2017 at 5:57
Adding an id
attribute:
<video id="video" width="480" height="400" controls="true" poster="">
<source type="video/mp4" src="video.mp4"></source>
</video>
You can attach the event ended
to your video:
With plain javascript:
document.getElementById('video').addEventListener('ended', function(e) {
// Your code goes here
});
With jQuery:
$('#video').bind('ended', function() {
// Your code goes here
});
Here is a comprehensive solution:
(The seek disabling function below comes from How to disable seeking with HTML5 video tag ?)
Assuming you have a video element with id "vid_id"
in the HTML, e.g.:
<video id="vid_id" controls>
<source src="whatever.mp4" type="video/mp4">
</video>
You can use these functions:
function vid_listen() {
var video = document.getElementById('vid_id');
video.addEventListener('timeupdate', function() {
if (!video.seeking) {
if (video.currentTime > timeTracking.watchedTime) {
timeTracking.watchedTime = video.currentTime;
lastUpdated = 'watchedTime';
} else {
//tracking time updated after user rewinds
timeTracking.currentTime = video.currentTime;
lastUpdated = 'currentTime';
}
}
if (!document.hasFocus()) {
video.pause();
}
});
// prevent user from seeking
video.addEventListener('seeking', function() {
var delta = video.currentTime - timeTracking.watchedTime;
if (delta > 0) {
video.pause();
//play back from where the user started seeking after rewind or without rewind
video.currentTime = timeTracking[lastUpdated];
video.play();
}
});
video.addEventListener("ended", function() {
// here the end is detected
console.log("The video has ended");
});
}
function vid_start() {
window.timeTracking = {
watchedTime: 0,
currentTime: 0
};
window.lastUpdated = 'currentTime';
}
Execute vid_listen()
any time after the document loaded. Execute vid_start()
any time before the video is started (or when a new analogous check is needed).
You can use:
function getPlayedTime(video) {
let totalPlayed = 0;
const played = video.played;
for (let i = 0; i < played.length; i++) {
totalPlayed += played.end(i) - played.start(i);
}
return {
total: totalPlayed,
percent: totalPlayed / video.duration * 100,
};
}
var vid = document.getElementById("myVid");
vid.onended = function() {alert("The video has ended");};
document.getElementById('myVideo').addEventListener('ended',myHandler,false); function myHandler(e) { alert("finished"); // What you want to do after the event }