Getting Started with xAPI: Four Lines of Code

Content isn’t easy to create. At least, good content isn’t. But what makes content good? What makes it effective? What is it about your content that makes it effective? What factors matter the most?

At the end of the day, what matters most about your content is how your consumers use it. Are they interacting with videos or activities? Are they just clicking through everything, or are they taking their time and consuming it? All of this is vital to know, because if the content isn’t being consumed, then what good is it? But you need to be able to track how (or if) your consumers are interacting with your content to know which are the good bits, and what should get cut out. And the best way to track how your consumers are using your content is to build Experience API (xAPI) statements into that content.

One of the issues standing in the way of a much wider adoption of xAPI is the belief that it’s somehow difficult to implement. And, in truth, the most popular rapid development tools certainly don’t make it easy. Their support of xAPI is lacking, at best, although ADL and DISC are doing what they can to improve the situation. But that’s no reason to give up! With just a little experience with JavaScript, adding the code to send xAPI statements is quite easy. In fact, all that you need in order to send an xAPI statement is four lines of code!

Before we focus on the specific mechanics of sending an xAPI statement, let’s look at the four steps you must take to send a statement:

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

Seriously, that is all it takes! And each of these steps is easily accomplished in a single line, once you know what the code looks like. And you don’t need to be a JavaScript wizard by any means. Not only is the code relatively simple, it’s pretty straightforward. There aren’t a lot of tricks needed to make it all work.

But I’m not a developer/programmer!

Instructional designers really should know this information! Even if you’ll never write a single line of code (let alone four), knowing and understanding these steps can be very helpful. Let’s say you want to track how consumers are interacting with a cool new activity you’re working on. By understanding the steps, you can make sure you build your activities so that there is a way to define the statement and send it when and where you want to. You’ll know, at each step in the activity, what data needs to be available and when. With that, you can design your activity accordingly.

Below is a complete, functional webpage where I can illustrate the JavaScript required to create and send a statement:

<!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:Tester@example.com",
                "name": "Your Name Here",
                "objectType": "Agent"
            },
            "verb": {
                "id": "http://example.com/xapi/interacted",
                "display": {"en-US": "interacted"}
            },
            "object": {
                "id": "http://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>

This page doesn’t actually do a lot, agreed. It presents the user with a single button. Upon pressing this button, it sends a statement that someone pressed the button. This example isn’t the most impressive use of xAPI you can imagine, I know. But without the burden of doing anything actually useful, it’s much easier to follow the xAPI code and see how easy it can be to implement!

Above, I listed the four steps needed to make xAPI work. Each of those four steps maps directly to a single line of JavaScript code. And each is included in this code example. Let’s take a look at each of them in a little more detail.

Step 1

Define a variable that holds the URL address of the LRS and the username and password to authenticate.

The first thing we need to do is to tell the content where to send the xAPI statements. This is a two-step process. The first step is to define a JavaScript variable containing the URL to the ADL website to find the LRS along with the user credentials you’ll use. In this example, I’m using the simple basic authorization here, which only requires a defined username and password. The line of code that accomplishes this task is:

var conf = {
             "endpoint" : "https://lrs.adlnet.gov/xapi/",
             "auth" : "Basic " + toBase64("xapi-tools:xapi-tools")
             };

I want to point out something here: I know that looks like three lines of text. But as far as the computer is concerned, it’s only a single actual line of code. In fact, I could rewrite the same code segment to look like this:

var conf = {"endpoint" : "https://lrs.adlnet.gov/xapi/","auth" : "Basic " + toBase64("xapi-tools:xapi-tools")};

If we look at this code, it contains a couple parts worth looking at:

var conf =

This bit tells the browser that we’re defining a JavaScript variable.

"endpoint" : https://lrs.adlnet.gov/xapi/

The next bit tells the browser the URL of the LRS endpoint to which you’ll send the xAPI statement defined later in the page.

"auth" : "Basic " + toBase64("xapi-tools:xapi-tools")};

This tells the browser what user credentials to use when communicating with the LRS. The “tobase64” function is used to encrypt the user credentials to make the process somewhat more secure.

And the curly brackets {} at the beginning and end of the line package it together as a single object that the variable can hold.

Note: There are other, more secure, ways to authenticate to your LRS (oAuth, for example). But this is the easiest way to get started and the easiest to demonstrate, so I’ll show this method for now.

Step 2

Tell your xAPI wrapper to use that variable for the LRS.

So now that we have the variable defined with the endpoint URL and user credentials, let’s tell the browser to use it! That is accomplished with this line:

ADL.XAPIWrapper.changeConfig(conf);

This function is defined as part of the ADL xAPI wrapper, a set of functions to make sending and managing the xAPI statements easier. It just sets this variable as the one to use for all of your statements. This may sound odd at first. Why would I create a variable to do this, then set that variable? As with all things programming, there are other ways to do this. But it does make it easier to manage the code and debug any problems if they should arise. So, while it’s not really necessary to do it this way, it is recommended.

Step 3

Create a variable to hold the xAPI statement.

The next step is to create a variable to hold your statement. Now, again, this will look like multiple lines of text because, well, it is! But the computer interprets all of this as a single line of code:

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

This is a very simple example of a statement. It contains the three required pieces (Actor, Verb, and Object) and simply says that a test user (Tester@example.com) has clicked on the button, and saves the text of the statement to the variable statement.

In a later article, I’ll detail how you can make changes to the statement to make it much more useful. But for now, this serves the purpose of demonstrating the ease with which you can start adding your own statements. And now that we have a statement, we can hit that final step, and send it!

Step 4

Send the statement.

We know where the LRS is, we have the credentials to use it, and we have a statement to send. Nothing left but to share our statement with the world!

var result = ADL.XAPIWrapper.sendStatement(statement);

This line does a few things worth looking at. First, it sends the statement. As with the code for Step 2, this function is defined by the ADL xAPI Wrapper:

ADL.XAPIWrapper.sendStatement(statement);

Now, technically, you can just issue this code by itself. It will send the statement to the LRS. However, the function will also return information that we can use, such as error codes in the event that the send fails. If the send succeeds, it will return the statement ID. If it fails, it will hold an error code. So it’s a good idea to create a variable to hold this information, which is why we start the line with:

var result =

Again, creating a variable called result will tell us if the send was successful, by holding the statement ID, or if not, by holding the error code returned by the LRS.

And that’s it! It’s that simple. By using these four lines of code in your activity, you can send just about any statement you want! Now, the more you want to customize the statements, the more complicated this can get.

Let’s do it again—with video!

But let’s take a look at another example. In this case, I’m sending statements recording what segments of a video the user is watching. This seems like it would be much more involved than simply pressing a button, right? Well, not really. Take a look:

   <script type="text/javascript">
var playFrom = 0;
jwplayer('mediaplayer1').setup({
  width: "480",
  aspectratio: "16:9",
  file: "./big_buck_bunny.mp4",
  autostart: false,
 });
// this adds the pop-up to ask for the user's name. We'll build the ACTOR definition
// with this first name
 var firstname = prompt("What is your first name?")

// Tell the content where to send the xAPI statements
 var conf = {"endpoint" : "https://lrs.adlnet.gov/xapi/",
   "auth" : "Basic " + toBase64("xapi-tools:xapi-tools")};

// Tell the browser to use the variable we just defined
 ADL.XAPIWrapper.changeConfig(conf);

// Record time index where user started watching
 jwplayer().onPlay(function(event){
  playFrom = jwplayer().getPosition()
 }); //end onPlay

// Send statement when someone pauses the video
 jwplayer().onPause(function(event){
  var position = jwplayer().getPosition()

//define the xapi statement being sent
  var pausestatement = {
   "actor": {
    "mbox": "mailto:" + firstname + "@devlearn16.com",
    "name": firstname,
    "objectType": "Agent"
   },
   "verb": {
    "id": "http://adlnet.gov/expapi/verbs/Play",
    "display": {
     "en-US": "Video Played"}
   },
   "object": {
    "id": "http://example.com/bigbuckbunnyvid.html",
    "definition": {
     "name": {"en-US": "Big Buck Bunny Video"},
     "description": {"en-US": "sample description"}
    },
    "objectType": "Activity"
   },
   "result": {
     "extensions":{
      "http://example.com/xapi/period_start" : playFrom,
      "http://example.com/xapi/period_end"     : position
     }
    }
    }; // end statement definition

// Send the statement to the LRS
  var result = ADL.XAPIWrapper.sendStatement(pausestatement);

 }); //end onPause

In this second example, I’m collecting which segments of the video the user is watching. When the user hits play, a variable is set with the timestamp of the video where he or she started. Then, when the user hits pause, another variable is set with the current timestamp of the video, and a statement is sent with that information to the LRS. In the above example, we’re building the statement with not only those two variables, but also setting the actor information with another variable that was defined by a simple pop-up window asking the user for his or her first name. I’ll go into more detail about how to use variables to build more adaptive statements in a future article.

But even with this added complexity and functionality, the four lines are still there! The line that follows the comment "//Tell the content where to send the xAPI statements" sets the variable to store the URL and user credentials for the LRS. The line that follows the comment "// Tell the browser to use the variable we just defined" tells the wrapper which variable to use for the destination LRS. Then we go into the function that runs when the user hits pause, jwplayer().onPause. In this function, we do two things: First we build the xAPI statement, the multi-line section that follows the comment "//define the xapi statement being sent" down to "//end statement definition"; then we tell the browser to send the statement, the single line that follows "//Send the statement to the LRS"..

No matter what you want to record with xAPI, it will always come back to those four steps and those four lines of code. You can build all kinds of activities, interactions, or data collections that may be very complicated in how they are implemented. In any of those instances, it’s still the same four-step process to send your statement.

An admission of guilt: I lied—a little

In truth, it’s not always four lines of code. First, you need to tell the browser where the xAPI wrapper files are. This is done with the two lines:

   <script type="text/javascript" src="./js/cryptojs_v3.1.2.js"></script>
   <script type="text/javascript" src="./js/xapiwrapper.js"></script>

So, really, there are six lines. But even that’s not really true. In the second example I use the first two lines of code described to tell the browser where my LRS is located. I only need to do that once per page. So if I wanted to send statements when the user hit play/pause, completed the video, changed the volume, etc.—each of those would only require two additional lines. One to create the statement, and one to send the statement. So it’s not actually four lines of code each time you want to send a statement. In fact, the more xAPI statements you send per page, the easier it gets!

Conclusion

What makes content good is not easy to define. What matters most is “what makes content good … for this audience.” And to find that, you need to know the audience. You need to know what that audience likes. The best way to do that is to monitor how they use your current products and then tailor future releases, building up the parts that get used the most and removing the parts that are often skipped over. xAPI is a great way to do that.

xAPI is still new and unfamiliar to many. But now, hopefully, by seeing the actual steps taken to connect to an LRS and to craft and send your statements, you’ll not only see that xAPI isn’t magic, but also that it’s very approachable and something you can start using today!

Learn more at xAPI Camp and DevLearn 2018

Are you ready to dig in and discover xAPI for yourself? Register now for the day-long xAPI Camp on Oct. 23, 2018, and learn why—and how—to use xAPI to move your eLearning to the next level. Stay for DevLearn 2018 Conference and Expo, Oct. 24 – 26, 2018 and extend your learning with creative and compelling keynotes, demonstrations, networking, sessions about xAPI, AR and VR, and data and measurement—and much more.

More Development

You May Also Like