The Getting Started with xAPI in Storyline Tutorial Series, by Devlin Peck @devpeck, was originally published at devlinpeck.com. Check out Devlin at the LMSPulse Elearning Success Summit 2020.
Get Started with xAPI, Part One: How to Write an xAPI Statement from Scratch
Are you ready to begin collecting learning experience data from the participants in 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.
Set up a 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.
On the next page, you need to select the checkbox to consent to be tracked, then click “Save”.
After saving your new tracking preference, you should follow the link on the left.
Now you can enter your info again, create a password, agree to the TOS, and click “Sign up”
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.
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.
Set up 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.
Build the JavaScript 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 parameters, 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) {
}
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. 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) {
const player = GetPlayer();
const uNamejs = player.GetVar("uName");
const 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 “const 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:
const 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):
const 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:
function send_statement(verb, verbId, object, objectId) {
const player = GetPlayer();<br>
const uNamejs = player.GetVar("uName");
const uEmailjs = player.GetVar("uEmail");
const statement = {
"actor": {
"name": uNamejs,<br>
"mbox": "mailto:" + uEmailjs
},
"verb": {
"id": verbId,
"display": { "en-US": verb }
},
"object": {
"id": objectId,
"definition": {
"name": { "en-US": object }
}
}
};
const 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:
const 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:
const 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 where 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) {
const player = GetPlayer();
const uNamejs = player.GetVar("uName");
const uEmailjs = player.GetVar("uEmail");
const conf = {
"endpoint": "https://trial-lrs.yetanalytics.io/xapi/",
"auth": "Basic " + toBase64("1212:3434")
};
ADL.XAPIWrapper.changeConfig(conf);
const statement = {
"actor": {
"name": uNamejs,
"mbox": "mailto:" + uEmailjs
},
"verb": {
"id": verbId,
"display": { "en-US": verb }
},
"object": {
"id": objectId,
"definition": {
"name": { "en-US": object }
}
}
};
const 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.
Now configure the trigger to “Execute JavaScript” whenever the user clicks the custom “Submit” button.
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.
Important notes: Wrap each argument in quotation marks, and ensure that there is a comma between each argument that you pass. Also, avoid any special characters (such as ?, !, #, etc.) when passing the “object” parameter.
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. 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!
Prepare the Storyline Project’s output folder
We need to publish the Storyline course before we can link it to the external JavaScript files (such as xapi-statement.js
).
The custom statements will send from any type of content package, so it does not matter if we publish the course as an HTML5 package, SCORM package, or 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”.
When the file is done publishing, select OPEN to open up the folder in your file explorer. Next, 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.
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.
Important note: If you don’t see the storyhtml5.html file in your output folder, that just means that you’re using the latest version of Storyline and publishing as HTML5. You will modify the “story.html” file instead (and only do this if you don’t see the storyhtml5.html file).
You’ll see a lot of code, but we’ll only be in this file for a minute. Copy the following two lines of code. They tell the 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 (or story.html) file. You can either scroll down or use Crtl + F to find the closing style tag. Paste the script tags between the closing style tag and the closing head 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 (or story.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”.
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:
If you see the statement there, then congratulations! You’ve successfully generated an xAPI statement from Storyline. If you’ve run into an error, then you should refer to the common xAPI and Storyline troubleshooting steps.
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.
2 Responses