How to Send an xAPI Statement from a Storyline Course

Welcome back to the Getting Started with xAPI Tutorial Series

Are you ready to begin collecting learning experience data from the participants taking your eLearning courses? If so, then you're in the right place. By following along with this final tutorial of the series, you'll learn how to generate custom xAPI statements to collect exactly the data you need from your Storyline course.

You do not need any coding knowledge coming into this tutorial. However, you should have completed Part 1 and Part 2 of this tutorial series before beginning this part, as you will be building on the work that you've already completed.

Setting up the Learning Record Store (LRS)

The first thing we'll do in this tutorial is set up the LRS, as this is where you'll be sending all of your xAPI statements. Feel free to use a different LRS, but we'll use the Yet Analytics Trial LRS for the purposes of this tutorial.

So, visit the Yet Analytics Trial LRS sign-up page, enter your information, and select "Create New Account".

Sign up for a free Yet Analytics Sandbox LRS

On the next page, you need to select the checkbox to consent to be tracked, then click "Save".

Consent to be tracked by Yet Analytics

After saving your new tracking preference, you should follow the link on the left.

Consent to be tracked by Yet Analytics

Now you can enter your info again, create a password, agree to the TOS, and click "Sign up"

Consent to be tracked by Yet Analytics

Check your email inbox to access the Yet Analytics confirmation email, click the link in the email, and sign in to your account. Once you're signed in successfully, select your Sandbox LRS.

Consent to be tracked by Yet Analytics

You can close the "try new dashboard experience" popup (if it still appears at the time you're reading this tutorial) and select the "Info" tab from the top toolbar.

This is where you can find all of the information you'll need to get your Storyline course communicating with your LRS. Leave this window open, as you will need the Endpoint, API Key, and API Secret during the next part of this tutorial.

Configuring the xapi-statement.js File

In this section, you'll finish coding the xapi-statement.js file so that it's ready to send statements to the LRS

Setting Up the Function and its Parameters

We need to create the JavaScript function that will send the xAPI statements to the LRS. Start by opening the xapi-statement.js file that you've worked on during the last two parts of the tutorial series. The JavaScript will get slightly more complex at this point, but fear not! Follow the syntax closely and you will be sending statements with ease.

First we need to wrap all of the code that we've written so far in a JavaScript function. A function is a block of code that performs a specific task; in this case, our task is to send an xAPI statement.

We can also set "parameters" for a function, which are essentially placeholders that you can use throughout the function. This is useful because you can pass "arguments" to these paremeters, which then populate the function with whatever data you pass. If this sounds confusing - don't worry. You'll see what I mean shortly.

So, above everything else in your xapi-statement.js file, add the following line of code:

function send_statement(verb, verbId, object, objectId) {

And don't forget to add a closing curly brace after the last line of code in your file. This tells the function where to stop!

Now our code within this function will only execute if we call the function, and, when we call it, we can include whatever values we'd like for the verb, verbId, object, and objectId parameters. However, this won't do much if we don't include the parameters in the xAPI object itself.

The next step is to replace the strings that we used in the previous version of our xAPI JSON object with the parameter names. For example, the verb's "id" value should be verbId and the verb's "display" "en-US" value should be verb. View the code below to ensure that you've placed the parameter names in the correct locations.

function send_statement(verb, verbId, object, objectId) {
  var player = GetPlayer();
  var uNamejs = player.GetVar("uName");
  var uEmailjs = player.GetVar("uEmail");
  {
    "actor": {
      "name": uNamejs,
      "mbox": "mailto:" + uEmailjs 
    },
    "verb": {
      "id": verbId,
      "display": { "en-US": verb }
    },
    "object": {
      "id": objectId,
      "definition": {
        "name": { "en-US": object }
      }
    }	
  }
}

Another way to think of it is that the parameters serve as variables for the future data that we will pass into the function. For example, once we have everything set up, we can execute the following line of code in Storyline using a JavaScript trigger:

send_statement("initialized", "http://adlnet.gov/expapi/verbs/initialized", "Write xAPI Statement Tutorial", "http://www.devlinpeck.com/write-xapi-statement");

When this code is executed, it will replace the variables in the xAPI object with the arguments that we passed, thereby giving us the exact statement that we had before modifying it. If you can't see why this is so powerful and efficient yet, then read on and prepare to be amazed at how easily we will be able to send statements from Storyline.

Using the ADL xAPI Wrapper

The next thing that we need to do to set up our function is assign the xAPI object to a variable. This is a necessary step to use the ADL xAPI Wrapper, which is a wrapper that eases the xAPI communication between the Storyline course and the LRS.

We can assign our xAPI object to a variable by typing "var statement = " before the object's opening curly bracket and adding a semicolon after the object's closing curly bracket. That part of the code should now look like this:

var statement = {
    //xAPI object (actor, verb, object) goes here
  };

After assigning the xAPI object to the "statement" variable, we need to use the xAPI Wrapper's functionality to tell the wrapper which statement to send. We do this by using the following line of code, which should be the last line of code in your JavaScript function (right before the final closing curly bracket):

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

This sets the result variable equal to the statement itself, which gets sent to the LRS. The "ADL.XAPIWrapper.sendStatement() function is provided by the wrapper, so that part needs to be typed exactly as shown above. If you've applied everything in this section correctly, then your code should now look like this:

Creating the "conf" Object

The last thing we need to do with this JavaScript file is configure it to work with your LRS, specifically. This is managed using the "conf" JSON object, which we can create in the same way that we created the other JSON objects. The conf object contains "endpoint" and "auth" properties. Therefore, add the following line of code right above where we define the "statement" variable:

function send_statement(verb, verbId, object, objectId) {
  var player = GetPlayer();
  var uNamejs = player.GetVar("uName");
  var uEmailjs = player.GetVar("uEmail");
  var statement = {
    "actor": {
      "name": uNamejs,
      "mbox": "mailto:" + uEmailjs 
    },
    "verb": {
      "id": verbId,
      "display": { "en-US": verb }
    },
    "object": {
      "id": objectId,
      "definition": {
        "name": { "en-US": object }
      }
    }	
  };
  var result = ADL.XAPIWrapper.sendStatement(statement);
}

Creating the "conf" Object

The last thing we need to do with this JavaScript file is configure it to work with your LRS, specifically. This is managed using the "conf" JSON object, which we can create in the same way that we created the other JSON objects. The conf object contains "endpoint" and "auth" properties. Therefore, add the following line of code right above where we define the "statement" variable:

var conf = {
  "endpoint": ,
  "auth": 
};

If you're using the Yet Analytics Trial LRS, then your endpoint will be "https://trial-lrs.yetanalytics.io/xapi/" (you can copy this from the Info tab that you opened earlier in this tutorial, but don't forget to add the '/' after the web address). You also need to set up the "auth" value so that it's ready to take the API Key and Secret. Update your conf variable so that it looks like this:

var conf = {
  "endpoint": "https://trial-lrs.yetanalytics.io/xapi/",
  "auth": "Basic " + toBase64("Key:Secret")
};

Important note: Ensure that there is a space between Basic and the quotation mark: "Basic ", not "Basic".

Copy the numbers from where it says "API Key" in the LRS Info Tab and paste it where it says "Key" in the code (right after 'toBase64'). Now copy and paste the numbers from it says "API Secret Key" to where it says "Secret" in the code. Looking at the code, the quotation mark before the key and the quotation mark after the secret key should remain.

Finally, we need to tell the LRS that we've updated the configuration. We can do this by using the following line of code immediately after defining the "conf" object:

ADL.XAPIWrapper.changeConfig(conf);

All together, your code should look like this:

function send_statement(verb, verbId, object, objectId) {
  var player = GetPlayer();
  var uNamejs = player.GetVar("uName");
  var uEmailjs = player.GetVar("uEmail");
  var conf = {
    "endpoint": "https://trial-lrs.yetanalytics.io/xapi/",
    "auth": "Basic " + toBase64("1212:3434")
  };
  ADL.XAPIWrapper.changeConfig(conf); 
  var statement = {
    "actor": {
      "name": uNamejs,
      "mbox": "mailto:" + uEmailjs 
    },
    "verb": {
      "id": verbId,
      "display": { "en-US": verb }
    },
    "object": {
      "id": objectId,
      "definition": {
        "name": { "en-US": object }
      }
    }	
  };
  var result = ADL.XAPIWrapper.sendStatement(statement);
}

Great work! If you've made it to this point, then rest assured that the most technical parts are behind you. There are a few more steps, but you're almost there.

Adding the JavaScript Trigger(s) in Storyline

In this section, you'll see why the function that we've set up is so powerful. Open up the Storyline project that you started in Part 2 to collect the user's name and email address. We want to send an xAPI statement whenever the user clicks the "Submit" button, so we'll need create a JavaScript trigger to do so.

First, select the "Create a new trigger" icon

Select the 'Create a New Trigger' icon

Now configure the trigger to "Execute JavaScript" whenever the user clicks the custom "Submit" button.

Configure the Storyline trigger

Select the ellipsis next to "Script", then you will see a textbox to enter the JavaScript code that you would like to run. This is where we are going to use the custom JavaScript function! Remember, our function takes four parameters: verb, verbId, object, and objectId. Using the information that you learned during Part 1 of this tutorial series, pass the appropriate arguments that we would like to send when the user clicks the submit button.

Insert the script to send the custom xAPI statement

Important notes: Don't forget to add a semicolon after the closing parenthesis. Also, wrap each argument in quotation marks, and ensure that there is a comma between each argument that you pass. If you'd like to copy and paste the code to ensure that you have it correct, you can do so here:

send_statement("initialized", "http://adlnet.gov/expapi/verbs/initialized", "Sample Course 1","http://www.devlinpeck.com/samplecourse1");

After adding the code to the JavaScript trigger, select "Ok" twice so that the trigger gets added to the course.

The best thing about this workflow is that you can send xAPI statements from anywhere that you can add a Storyline trigger, and all you need to do is switch out what information you'd like to send via the arguments. For example, if you want to send a "completion" statement when the user arrives at the course completion slide, you can add the following JavaScript trigger when the timeline starts on that slide:

send_statement("completed", "http://activitystrea.ms/schema/1.0/complete", "Sample Course 1","http://www.devlinpeck.com/samplecourse1");

The possibilities are vast, but you probably get the idea. If you have any questions about the types of statements you can send, feel free to ask away in the comments. However, we're not done yet. The final thing you need to do is make sure that your Storyline course can speak to your JavaScript files. We'll do this in the next section!

Modifying the Storyline Project's Output Folder

You can't link your Storyline project to your external JavaScript files (such as xapi-statement.js) until you've published your Storyline course. It's also important to note that your custom statements will work from any browser, so it does not matter if you publish the course as an HTML5 package, SCORM package, or built-in xAPI package. We're going to keep it simple and publish as HTML5.

From Storyline's "HOME" tab, select "Publish". After that, select "Web", then press "PUBLISH".

Publish the course as an HTML5 web package

When the file is done publishing, select OPEN to open up the folder in your file explorer. Next, you need to download the xAPI Wrapper's JavaScript file to this folder, as this is what let's us take advantage of the wrapper. You can download the .js file here, which is a direct link to the official download. Save the xapiwrapper.min.js file to your Storyline Output folder, or move it there from your downloads folder once it's finished downloading.

Important note: Ensure that the xapiwrapper.min.js file is in your published Storyline Output folder before continuing.

Save the xapiwrapper file to your published Storyline output folder

With the xapiwrapper.js file taken care of, you need to add your xapi-statement.js file (the one that you've been working on throughout these tutorials) to the published output folder. I recommend keeping the original saved somewhere safe on your hard drive, as you will be able to use this template for many different Storyline projects.

Once both of these files are in the output folder, we need to tell the Storyline course how to access them. We can do this by right-clicking the "story_html5.html" file and opening it with your text editor of choice.

Open the story_html5.html file with your text editor

You'll see a lot of confusing code, but we'll only be in this file for a minute. Copy the following two lines of code, which tell the main story_html5.html file where to access additional JavaScript scripts.

<script type="text/javascript" src="xapiwrapper.min.js"> </script>
<script type="text/javascript" src="xapi-statement.js"> </script>

Important note: If you've changed the name of your xapi-statement.js file, ensure that you update it in the script tag that you copied above.

With both of the script tags copied, look back to the story_html5.html file. You can either scroll down or use Crtl + F to find the closing tag. Paste the script tags between the closing style tag and the closing tag.

Add the script tags beneath the closing style tag

With that done, save the file and feel free to close it. Our xAPI statements are ready to fire.

Testing the xAPI Statement

To make sure that your xAPI statements generate as desired, go ahead and open up the project's story_html5.html file in your browser of choice (you can usually do this just by double clicking the file from your file explorer). Fill out your name and email address, then click "Submit".

Enter your name and email address then click Submit to test the xAPI statement

If you go to your LRS tab and close the Info pop-up box (or, if you've closed your LRS, then you need to sign back in and select your Trial LRS), then you should see that you've generated a statement. Scroll down through the data visualization tools to see your statement, stream, which will look like this:

Scroll down to view your xAPI statements in Yet Analytics LRS

If you see the statement there, then congratulations! You've successfully generated an xAPI statement from Storyline. If you've run into an error, try posting it in the comments below and we will do our best to help you. Feel free to attach screenshots so that we can isolate your issue better.

Finally, if you've learned from this tutorial, I'd appreciate it if you could share it on LinkedIn or Twitter to reach as many eLearning practitioners as possible. The quicker we all get on board with xAPI, the quicker we can start leveraging its potential as an industry.