Track Video Interactions with xAPI Statements

(Editor’s note: This article will notdisplay properly on a smartphone, and possibly not on a small tablet. We recommendviewing it on a desktop system, preferably one with two displays.)

In my previous article, I explained the steps youneed to take to send an xAPI statement. By way of quick review, those stepsare:

  1. Define avariable that holds the URL address of the learning record store (LRS) and theusername and password to authenticate
  2. Tell thebrowser to use that variable for the LRS
  3. Create avariable and define the xAPI statement
  4. Send thestatement

In thisarticle, we’ll look at how to start programmatically adding meaningful data tothose statements using data available from your page or LMS. Just like theprocess of sending a statement, building one is pretty easy, once you learn acouple of simple programming concepts and plan out what you need and whenyou’ll need it.

But I’m not a developer or programmer!

Knowinghow to build statements is of immense benefit to instructional designers too! Keepin mind that the current versions of some of the popular rapid-developmenttools only really send xAPI statements for the traditionally SCORM-like events(launch, suspend, completion, pass, fail, etc.). So if you want to make themost of xAPI, you’ll need to add some custom code to your products. But evenbefore that, knowing what information you’ll need and where to find it willhelp you make smart design decisions that will allow your online courseware to makesure the data is there to do whatever you need it to do.

(Editor’s note: We recommend that readersopen another copy of this article on a new browser tab, or display another copyof this article on a second monitor if one is available. You will be lookingback and forth from Anthony’s text to his code listings.)

A couple of things you should know

The first thing you should understand is thatmost of the xAPI code you’ll ever experience (no pun intended) will be writtenin JavaScript. Whether you write the code yourself or the code is the productof a rapid development tool, it will be in JavaScript. Which is a good thing. Becausethe second thing you need to know is how your browser, and the Internet atlarge, views code and script. Let’s take a look at this statement:

var statement = {             "actor": {                "mbox": "mailto:[email protected]",                "name": "Your Name Here",                "objectType": "Agent"            },            "verb": {                "id": "https://example.com/xapi/interacted",                "display": {"en-US": "interacted"}            },             "object": {                "id": "https://example.com/button_example",                "definition": {                    "name": {"en-US": "Button example"},                    "description": {"en-US": "Example xAPI Button"}                },                "objectType": "Activity"            } }; //end statement definition

That’s anicely formatted statement. It’s well indented to help you see where each ofthe components (Actor, Verb, and Object) are defined. It’s easy to read. And,it’s just a pleasure to look at. It’s also all for you, the human. The fact is,the computer sees the above code like this:

Varstatement={"actor"{"mbox":"mailto:[email protected]","name":"YourNameHere","objectType":"Agent"},"verb":{"id":"https://example.com/xapi/interacted","display":{"en-US":"interacted"}},"object":{"id":"https://example.com/button_example","definition":{"name":{"en-US":"Buttonexample"},"description":{"en-US":"ExamplexAPIButton"}},"objectType":"Activity"}};//endstatementdefinition

It maynot seem like it, but that’s a good thing. xAPI statements are anything butprecious or fragile. Yes, they must conform to certain standards. But they aretreated much like any other string or JavaScript object you might have tomanage. You have handy tools like the ADL xAPI wrapper you met in the firstarticle to help you. So you can make all kinds of changes to your statements. Youwon’t hurt anything. You won’t break the computer. You won’t break the Internet.So yes, the first example looks somewhat imposing at first. But the fact isthat it’s all for your viewingpleasure. xAPI statements are a pretty hardy bunch.  

Also, JavaScript string variables are defined by using doublequotes. For example: “Hello World!” is a string. The best part about them isthat they can very literally just get added together to form bigger, morecomplex strings. Try this: Open the JavaScript console for your browser (InChrome you open the console by selecting View > More Tools > Developer Tools> JavaScript Console). In the console window, type the following, then hitreturn or enter.

             “Hello ” + “world!”

Theconsole will print “Hello world!”, or “Helloworld!” if you forgot the spaceafter “Hello.” (See Figure 1.)

Figure1: The classic “Hello world!” statement in aconsole window

This isa vital thing to know, as we’ll use this a couple of times in the belowexamples. Again, the Internet is really robust. You’re not going to break anything you can’t easily fix! And it isgenerally really easy to fix the things we’ll be looking at below if you make atypo or something.

So, withthese things in mind, let’s break out some code.

Starting with a basic example

Below is a complete, functional webpage to showa very simple statement when a user clicks on the button.

<!doctype html><head>      <!-- Includes for ADL's xAPI Wrapper -->    <!-- Download the files from: -->    <!-- https://github.com/adlnet/xAPIWrapper -->    <script type="text/javascript" src="./js/cryptojs_v3.1.2.js"></script>    <script type="text/javascript" src="./js/xapiwrapper.js"></script>    <!------------------------------------->            <script>    function send_statement(){        var conf = {              "endpoint" : "https://lrs.adlnet.gov/xapi/",              "auth" : "Basic " + toBase64("xapi-tools:xapi-tools")              };        ADL.XAPIWrapper.changeConfig(conf);                  //define the xapi statement being sent        var statement = {            "actor": {                "mbox": "mailto:[email protected]",                "name": "Your Name Here",                "objectType": "Agent"            },            "verb": {                "id": "https://example.com/xapi/interacted",                "display": {"en-US": "interacted"}            },            "object": {                "id": "https://example.com/button_example",                "definition": {                    "name": {"en-US": "Button example"},                    "description": {"en-US": "Example xAPI Button"}                },                "objectType": "Activity"            }        }; //end statement definition         // Dispatch the statement to the LRS        var result = ADL.XAPIWrapper.sendStatement(statement);        }    </script></head><body>    <button type="button" onclick="send_statement()">Send Statements</button></body></html>

In theexample you just saw, the statement says … very little of use. It says that ananonymous user interacted with a button. This is good if you want to know howmany times the button has been clicked. But that’s it. It won’t tell you howmany different people have clicked the button, or even who has clicked thebutton. It just says that the button got clicked. But you can easily add thefunctionality to see who gave the button a click.

TheActor, in this statement, would describe who clicked the button. And thatperson is defined in the above example as:

"actor": {    "mbox": "mailto:[email protected]",    "name": "Your Name Here",    "objectType": "Agent"},

TheActor ID is defined, in this case, by the line

"mbox": "mailto:[email protected]"

The mboxkey tells the LRS we are using an email address as the Actor ID. And if youlook closely, you’ll notice that the email address is actually a string. So wecan edit this pretty easily.  The importantbit that must be there is the “mailto:” piece. And, as we saw before, if wehave the user’s email address, we can simply add it to “mailto:” and we’ll haveour Actor ID. So we need the user’s email address.

Thereare a few ways to do this. One example is to simply ask them. So we’ll add a line to the code so it reads like this:

<script>    var email = prompt("What is your email address?")    var conf = {          "endpoint" : "https://lrs.adlnet.gov/xapi/",          "auth" : "Basic " + toBase64("xapi-tools:xapi-tools")        };    ADL.XAPIWrapper.changeConfig(conf);</script>

Now,when the page loads, a pop-up will ask the user for his or her email address. Itwill capture the user’s email address as a string. And, as you’ll recall fromabove, you can just add two strings together to make a larger one! So we’ll usethe email variable to define the Actorlike this:

"actor": {        "mbox": "mailto:” + email,        "name": "Your Name Here",        "objectType": "Agent"},

It’sthat easy. Well … kind of. There is a problem. The learning record store (LRS) won’tcheck to make sure the email address is completely valid. But it will rejectthe statement if the email address is not correctly formatted([email protected]). What if the user enters something like “I don’t wanna”? Thestatement will get rejected. But there is another way to identify your Actor. Youcan use the username and site URL for your LMS, LRS, or hosting site. In thiscase, the Actor would be defined like this:

"actor": {    "account": {        "homePage": "https://www.example.com",        "name": email        },    "objectType": "Agent"},

Again,we’re just using the string we collected from the prompt() pop-up, but now, instead ofrequiring an actual email address, it’s using the username at your LMS. This isa fantastic way to do it, too. Because xAPI can also be used with SCORMcontent. For example, if you are using the Rustici SCORM driver for your SCORMcontent, you could replace the line we added above with this one:

<script>    var email = SCORM_GetStudentID();    var conf = {          "endpoint" : "https://lrs.adlnet.gov/xapi/",          "auth" : "Basic " + toBase64("xapi-tools:xapi-tools")        };    ADL.XAPIWrapper.changeConfig(conf);</script>

Thatwill pull the username, or user ID, for the student from the LMS. Then, for thehost, just list the URL of your LMS.

Capturing video interactions

Let’stake a look at another example. This time, capturing activities from a page-servingvideo. This time, we’ll look at a web page that plays the open-source video Big Buck Bunny. The page will prompt theuser for an email address and build the Actor based on the email addressentered. It will also build the Verb based on what the user does (clicks play,clicks pause, or the video completes).

Note: For this example, I’ll usestraight HTML5 video using the <video> tag. Butthe concepts easily apply to any player such as JWPlayer.

<!doctype html><head>      <meta charset="utf-8">      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">      <title>xAPI Video Sample</title>    <!-- The video used is Big Buck Bunny under Creative commons 3.0.  -->    <!-- You can find the movie here: -->    <!-- https://peach.blender.org/download/ -->          <!-- Includes for ADL's xAPI Wrapper -->    <!-- Download the files from: -->    <!-- https://github.com/adlnet/xAPIWrapper -->    <script type="text/javascript" src="./js/cryptojs_v3.1.2.js"></script>    <script type="text/javascript" src="./js/xapiwrapper.js"></script>       <script>        // this adds the pop-up to ask for the user's name.          We'll build the ACTOR definition        // with this first name                                  var email = prompt("What is your email address?");        // Set the URL and user credentials for the LRS        var conf = {        "endpoint" : "https://lrs.adlnet.gov/xapi/",            "auth" : "Basic " + toBase64("xapi-tools:xapi-tools")                      };        // Tell the xAPI driver to use these creds        ADL.XAPIWrapper.changeConfig(conf);        // This function will programmatically build the statement using variables        function sendxAPIStatement(userName, action) {                    var statement = {                "actor": {                    "account": {                        "homePage": "https://www.example.com",                        "name": userName                    },                    "objectType": "Agent"                },                "verb": {                    "id": "https://example.com/expapi/verbs/video/" + action,                    "display": { "en-US": action }                },                "object": {                    "id": "https://example.com/bigbuckbunnyvid.html",                    "definition": {                        "name": { "en-US": "Big Buck Bunny Video" }                    },                    "objectType": "Activity"                }            };            ADL.XAPIWrapper.sendStatement(statement, function(){});             // adding an empty function() at the end of sendStatement tells it to fire asynchronousely       };    </script>    <!-- -------------------------------- --></head><body>    <div align="center">        A quick example of using xAPI to track jwplayer events.        <br/><br/>    </div>    <!-- This sets the HTML video player provided by the browser -->    <div align="center">        <video id="mediaPlayer" width="720" controls>            <source src="big_buck_bunny.mp4" type="video/mp4">            Your browser does not support HTML5 video.        </video>    </div>    <script>         // this sets up the Variable "Vid" to point to the video player        // so we can interact with it.        var vid = document.getElementById("mediaPlayer");                // When the user hits Play...             vid.onplay = function() {        sendxAPIStatement(email, "Play")        }; // End onPlay()        // When the user hits Pause...             vid.onpause = function() {        sendxAPIStatement(email, "Pause")        }; // End onPause()        // When the video completes             vid.onended = function() {        sendxAPIStatement(email, "completed")        }; // End onEnded()    </script>     <!—  everything between <p> and </p> is all one line - no line breaks —>    <p><a href="https://peach.blender.org/about/"><img style="float: left;" title="cc-by" src="https://peach.blender.org/wp-content/uploads/cc-by.jpg" alt="" width="100" height="35" /></a></p></body></html>

In this latestexample, we modify Actor and Verb in the statement using the methods we lookedat in the earlier examples. While defining the Actor we simply use the variableas the value for the Name key. 

"actor": {       "account": {                "homePage": "https://www.example.com",                "name": userName       },       "objectType": "Agent"},

In theVerb definition, we use both methods, defining the verb URL by combining thebase URL with the string variable action. Then we use that same variable as thevalue in the key pair for the display value:

"verb": {       "id": "https://example.com/expapi/verbs/video/" + action,       "display": { "en-US": action }},

In conclusion

You canuse xAPI to track just about anything you can imagine. But you have to be ableto build the statements in order to send them. And while the above is far froma thorough review of all the ways you can build statements programmatically, itshould give you enough to help you get started. As you can see, as it is withmost things, the programming is not all that difficult, and is verystraightforward. The hardest part will be in designing your activities, makingsure you build them so that you can get the data you need at the point thatyou’ll want to send your statements. Once you’ve got that covered, the rest iscake.

In thenext article, we’ll look deeper into tracking video consumption. We’ll alsolook at tracking test answers to start correlating test results to videoproduction, so we can see if those videos are getting the job done!

Share:


Contributor

Topics:

Related