Referencing Embedded Vimeo Video with Javascript API

Nov 25, 2019

I have inserted a Vimeo video into a course using Insert > Video from Website. It plays fine using the Vimeo player. However, I would like to use the Vimeo API in an Execute Javascript trigger to access events, methods and other properties about the video.

I have included the Vimeo API Javascript library in the published story_html5 file, and I am attempting to make a connection to the Vimeo player.

Where I am running into a challenge is that Storyline creates an iFrame to hold slide content, and then the embed code also has an iFrame nested within the slide. I can't quite figure out how to point to it. Below is a sample of what I have attempted. Any suggestions or other approaches will be greatly appreciated. Thanks!

 

Trigger: Execute JavaScript when timeline reaches 5s

(delayed the call to ensure the iframe had time to load)

 

var iframe = document.querySelector('iframe').contentWindow;

var cframe = iframe.document.getElementById('ckpt1');

var player = new Vimeo.Player(cframe);


player.on('pause',function(){

    alert("Video paused");

});

 

The variable iframe should contain the iframe created by Storyline to hold slide content, the variable cframe should contain the nested iframe with id='ckpt1', and the variable player should be the Vimeo player in the cframe.

I have an on pause event that should alert me that the video has been paused in the Vimeo player. 

 

Thanks in advance for your help!

 

 

 

19 Replies
Fred Tacon

Thanks, Seth! After I posted this, I found an old thread from someone else trying to do something similar with Wistia instead of Vimeo. They put all of their scripting within the Embed code window for the web video. I tried that with the Vimeo video, and so far it works! Still testing to do, but it is encouraging. If it doesn't pan out, I will look into your suggestions. Thanks!

Fred Tacon

Hi, Kate!  Yes, there are events and methods in the Vimeo API that will tell you when the video plays, how much has been viewed, and when it is complete. I've actually set our completion credit at 80% just in case someone forwards to the next page in the course before the video is completely finished. The % complete triggers a change to a Storyline variable.

Here is what I have put into the embed code for each Web Video object. Let me know if you have questions about it. There's also the URL to the Vimeo API reference guide at the bottom.

<!-- VIDEO #1 -->

<iframe id="ckpt1" src="https://player.vimeo.com/video/#########?autoplay=1&autopause=0" width="640" height="360" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe>

<script src="https://player.vimeo.com/api/player.js"></script>

<script>

  var iframe = document.querySelector('iframe');
  var player = new Vimeo.Player(iframe);
  var SLplayer = parent.GetPlayer();

  player.on('timeupdate', function(data) {
    var perc = parseFloat(data.percent);
    var ckpt = SLplayer.GetVar("ckpt1");
        if (perc > 0.8){
            if (ckpt == 0) {
                SLplayer.SetVar("ckpt1",1);
            };
        };
  });

</script>

 

Vimeo API reference: https://developer.vimeo.com/player/sdk/reference

Sara  Amado
Fred Tacon

Hi, Kate!  Yes, there are events and methods in the Vimeo API that will tell you when the video plays, how much has been viewed, and when it is complete. I've actually set our completion credit at 80% just in case someone forwards to the next page in the course before the video is completely finished. The % complete triggers a change to a Storyline variable.

Here is what I have put into the embed code for each Web Video object. Let me know if you have questions about it. There's also the URL to the Vimeo API reference guide at the bottom.

<!-- VIDEO #1 -->

<iframe id="ckpt1" src="https://player.vimeo.com/video/#########?autoplay=1&autopause=0" width="640" height="360" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe>

<script src="https://player.vimeo.com/api/player.js"></script>

<script>

  var iframe = document.querySelector('iframe');
  var player = new Vimeo.Player(iframe);
  var SLplayer = parent.GetPlayer();

  player.on('timeupdate', function(data) {
    var perc = parseFloat(data.percent);
    var ckpt = SLplayer.GetVar("ckpt1");
        if (perc > 0.8){
            if (ckpt == 0) {
                SLplayer.SetVar("ckpt1",1);
            };
        };
  });

</script>

 

Vimeo API reference: https://developer.vimeo.com/player/sdk/reference

Thanks, This was helpful

Matt Garton

Fred (or anybody), I'm hoping you can help me. I'm trying to do what many others are doing for Vimeo, have Storyline detect the end of the video and auto-advance. This is what I got and it's not working:

I'm using your SL variable 'ckpt1' to keep it easy to get it working... I assume i can change "ckpt1" in all instances to whatever I need as I have a ton of these to do in my course.

In Storyline, I have: (  '  '  around the variable text)

When 'ckpt1' changes
Jump to slide 'next slide'

I've also done it with option:

If 'ckpt1' = '1'

In the Video Web Embed, I have:

<iframe id="ckpt1" src="https://player.vimeo.com/video/xxxxxxxx" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>

<script src="https://player.vimeo.com/api/player.js"></script>

<script>

var iframe = document.querySelector('iframe');
var player = new Vimeo.Player(iframe);
var SLplayer = parent.GetPlayer();

player.on('timeupdate', function(data) {
var perc = parseFloat(data.percent);
var ckpt = SLplayer.GetVar("ckpt1");
if (perc = 1){
if (ckpt == 0) {
SLplayer.SetVar("ckpt1",1);
};
};
});

</script>

This is with us trying to use you 80% to be 100% instead...to trigger the slide advance.
We (my team) tried to use  player.getDuration().then(function(duration) {
From the API for Vimeo with little success

 

<script>
var iframe = document.querySelector('iframe');
var player = new Vimeo.Player(iframe);
var SLplayer = parent.GetPlayer();


player.on('play', function() {

});

player.getEnded().then(function(ended) {
SLplayer.SetVar("ckpt1",1);
});

</script>

 

Need help! Thanks

Fred Tacon

Hey, Matt. I think you just need to make it  'if (perc == 1)'  and it should work. You are just missing an '='.  We did find that because the time update loop was so fast, that if we tried to test 'perc' equal to a value, sometimes it would never match the value exactly, and so it would never trigger. I think you should be ok since the value shouldn't go higher than 1. If you still have trouble, though, you might try 'if (perc > 0.98)' so it listens for the video being almost complete. Hope this helps. Let me know if you have other questions.

Matt Garton

Hi Fred,

First, truly grateful for you help.

I must be missing something small still. So i changed it to
if (perc > .1){

just to test it and not have to sit through a 28m:45s video.

I hit play and let it roll, but it hits the 3 minute mark and was still playing.

This is what is in the file now (minus the xxxxxxx in the vimeo address)

<iframe id="ckpt1" src="https://player.vimeo.com/video/xxxxxxxx" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>

<script src="https://player.vimeo.com/api/player.js"></script>

<script>

var iframe = document.querySelector('iframe');
var player = new Vimeo.Player(iframe);
var SLplayer = parent.GetPlayer();

player.on('timeupdate', function(data) {
var perc = parseFloat(data.percent);
var ckpt = SLplayer.GetVar("ckpt1");
if (perc > .1){
if (ckpt == 0) {
SLplayer.SetVar("ckpt1",1);
};
};
});

</script>


All of that is in the web video embed window

Trigger in Storyline360:

Variable Triggers

name: ckpt1
When ckpt1 changes
- Jump to slide next slide


ckpt1 is a number variable, default value 0

I also tried with the option value 'if ckpt1 = value 1',   no go

Thoughts? Again, truly appreciate it.

Matt Garton

I've also been trying to play with this one, but can't get it to work either:

<script>
var iframe = document.querySelector('iframe');
var player = new Vimeo.Player(iframe);
var SLplayer = parent.GetPlayer();
player.getEnded().then(function(ended) {
var ckpt = SLplayer.GetVar("ckpt1");
if (ckpt = 0) {
SLplayer.SetVar("ckpt1",1);
};
};
});
</script>

Fred Tacon

Hey Matt. My apologies, I have not had time to look into this further. I will try to test it on my end by the end of the week. It might be hard to troubleshoot with out seeing your whole project, but I'll try to reproduce the scenario. One thing I did a lot when I was testing the solution initially was to write the perc value to the console on every time update and watch it while the video was playing so I could see what the value was doing. You could also write the value of ckpt so you could see if it ever changed from 0 to 1. 

Something like...

player.on('timeupdate', function(data) {
var perc = parseFloat(data.percent);
var ckpt = SLplayer.GetVar("ckpt1");

console.log(perc);

console.log(ckpt)


if (perc > .1){
if (ckpt == 0) {
SLplayer.SetVar("ckpt1",1);
};
};
});

I will get back with you as soon as I can. Thanks!

Fred

 

Matt Garton

Hi Fred,

I appreciate any help I truly do, and understand you have your own work/problems. So please again, accept my thanks. I'm sure this will help a ton of people if we(you mostly!!!!) can come up with something as it's a pretty common request and most of the solutions besides yours involve an external .html hosted somewhere. Not ideal and doesnt work for us.

Here's is what I found, I ran the video in Chrome and FireFox with Console up and nothing came up when I expected it to (eg. around 10% of the video viewed). 

I did dig into the publish can confirmed that code appears in an HTML file in the "story_content" folder. So the code from the video web object is making it into the publish. In fact, I just realized I can edit the code in the html and reload instead of republishing every time....sigh.....

Given that I saw nothing in the console when it past the 10% mark (and I let it run to 20%) - makes me wonder if the webobject in SL and Vimeo simply aren't talking to each despite the fact that's what the code is for. Just my feelings.

The project file is just a test bed to get something to work. I'm happy to wetransfer it to you if it helps. It's just a 3 slide test file with the video on slide 2. Once I have it working, I'll incorporate it into the actual course on a bigger scale (multiple videos).

I've event tried making it "Show" a button to allow the used advance the slide instead of just triggering an advance. No go.

Attached here is what the html file output looks like (xxxxxxx for the Vimeo id - I also removed all the 'allows' for vimeo (fullscreen, etc...) just now as I got a error on that line in console about preventing frame crosstalk and wanted to remove that as a possible problem.

I'll keep trying and report back, but I'm just at a loss here.

There's nothing I need to do in the file beyond putting it in the Web Video Object right? Just ruling out possibilities.

Fred Tacon

Matt,

My apologies. I may have forgotten a key thing that (hopefully) is the root of your troubles. Chrome has an annoying cross-origin restriction when you are running scripts locally, and it will prevent the course from connecting with the Vimeo API. When you publish the same course to a web server, you won't have that problem. Firefox may be the same way, though we don't use it here, so I can't test that. However, Microsoft Edge does not have the same restrictions and will allow the scripts to run locally. So, if you try your course in Edge, you might get the results you are hoping for. So sorry for this oversight. It's been awhile since we tested all of this locally, so it slipped my mind.

I have attached a super simple example that I created that works locally in Edge.

One thing to note is that the way I have it set up, it only works once. After the ckpt1 variable updates to 1, if the user navigates back to that page and watches the video again, it will not auto-forward the second time. You could have the variable reset to 0 each time the page is visited, if you wanted to ensure that it worked every time.

Let me know if this works for you or if you have additional questions. Thanks!

Fred

Matt Garton

Hi Fred,

I sent a reply yesterday morning, but it didn't go through I guess...sad cause I left instructions for how people can use this. But they can likely gleam from from the thread!

But yes, I figured out what you mentioned. Chrome was blocking it. I saw the error in console after you recommended watching it for variable changes - I got the error there and looked it up.

Once I uploaded to our testing LMS it worked fine!

Much thanks for all your help. Truly.

And good note about returning to the slide. Thankfully, we've changed it to be that the trigger makes a button appear that allows the user to advance (we aren't using the built-in UI). 

Have great weekend and thank you!


Fred Tacon

Hey, Dan. I am glad you have found this helpful. Yeah, Chrome has been a pain to deal with. But, we did not have to create any Storyline triggers to get autoplay to work. We added a couple things to the iframe code for each embedded video that seems to do the trick (see below). We added autoplay=1&autopause=0 to the video URL, and we added allow="autoplay; fullscreen" as an iframe attribute.

<iframe id="pre" src="https://player.vimeo.com/video/#########?autoplay=1&autopause=0" width="640" height="360" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe>

Have you tried running your course from a web server? We found that the cross-origin issue only affected us when we were running a course locally, and it went away once we published it online.

If this approach does not work for you, another thing to try is putting a non-video Storyline page before the video page, a title screen maybe, and set a trigger to auto-advance after a few seconds. Doing that seems to satisfy Chrome that it is a user action and will allow the video to autoplay (with the iframe code above).

Another option, though I will admit that I have not tried it as a solution to autoplay, is using the Vimeo player SDK. Since we call the player to monitor video progress, you can also use the player events to play and pause the video. Perhaps you could call the play event programmatically to get it to play as soon as it loads. Worth a try if the other approaches don't work.

Hope this helps. Let me know if you have any other questions. Thanks!

Fred

Dan Lidholm

Thanks Fred (and @Matt Garton) for your replies.

When I test the code below it does not auto start.

<iframe id="pre" src="https://player.vimeo.com/video/#########?autoplay=1&autopause=0" width="640" height="360" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe>

According to this article ( https://vimeo.zendesk.com/hc/en-us/articles/115004485728-Autoplaying-and-looping-embedded-videos) the video must be muted to be able to autostart.

Lucky me, that the current production just have videos are without sound.

So, to autostart the Vimeo video the code has to be:

<iframe id="ckpt1" src="https://player.vimeo.com/video/#########?autoplay=1&autopause=0&muted=1" width="540" height="960" frameborder="0" allow="autoplay; fullscreen" allowfullscreen="" muted=""></iframe>

Unfortunately, there seem to be no way to activate volume control or unmute button on the Vimeo player when autoplay is activated.

Great if someone could find a way to handle that sound problem.

@Fred, great idea to try with the Vimeo SDK. I'll may take some time to try to dive into it. It could solve the sound problem.

Fred Tacon

I know that it is not supposed to play with sound, but we are able to do it using the code described without issue. Very strange. But, I am glad that sound is a non issue for you at the moment! It's hard to say for sure what might be different for you than for us, but I'd be glad to take a look at your Storyline file if you wanted to share it. Thanks!