Adventures in xAPI Implementation: The Sending Statements Saga
Tags: xapi, elearning, storyline, scormcloud
Published: 2020-06-23 17:36:36

So I fell in love with xAPI quickly - and why wouldn't I? The company I work for provides training for other companies, and with SCORM courses, we had little to show clients other than a completion or basic quiz score. There was very little to help us create an idea of what the impact was, and very little to help us determine what was or wasn't successful.

Considering we have to be ready to serve our content to any LMS, it's not like xAPI solved all of these problems on its own, but knowing we wanted to start creating content around it, we at least knew where to start looking in order to make this happen.

That brought us to SCORM Cloud - a service known to many in eLearning as the go-to place for testing your eLearning's functionality - I don't know how many forum posts I've read that have boiled down to - "If it doesn't work in SCORM Cloud, it's your fault, if it does work in SCORM Cloud, it's the LMS' fault." Even if that's all SCORM Cloud could do, it is an extremely valuable resource, but they actually have some other incredible features that really came to save us - namely, Dispatch.

Dispatch lets you take the course that you have hosted in SCORM Cloud and generate a tiny tiny package file that can be loaded into a different LMS. It handles functions like registration and version controls, but one of the more amazing things it does is take your xAPI course, and make it compatible with any LMS that supports SCORM 1.2 - which is basically every LMS.

So now we cleared that hurdle and began to focus on the statement strategy. Because of the way data goes into the LMS, it's important to know what you can and can't query, and how those results come back, especially if you want to eventually get into visualizing your results (which I will get to in the next post). 

xAPI statements are comprised of three components:
- actor
- verb
- object

By default, Storyline will send some basic tracking statements for you when you publish your course as Tincan/xAPI, and those end up looking like:

"Jamie Davis experienced (slide name)"

While it's great that they support xAPI out of the box, these statements will only be useful in very specific settings, like branched courses, where you may want to see which slides are being viewed most/least often - they're still providing very little context to the learning. Considering the scope of what you can define with an actor, verb, and object, it would be nice to track more.

When I first started looking for information on how to send custom statements (because Storyline does not yet have a built-in way to expand on these), I began following tutorials that mentioned tweaking the course's code and including other files in order to achieve this. It was cumbersome, and initially limited the amount of custom statements I was willing to put in, because I had to take so many steps to test any statements I added.

Then one day, I noticed statements were coming into the LMS without my having made any modifications to the Storyline output! After some careful investigation, I realized that Storyline was now including TinCan functions that I had previously needed to add in myself, including the sendStatement function and the LMS setup - so no modifications were needed at all, I literally just had to write the javascript to send the statements!

So what does that look like? Kind of like this:

![visual of the code to send statements](https://dev-to-uploads.s3.amazonaws.com/i/u6nmzbsx9srynjd7h2dh.png)

Let's walk through it real quick - because you may have already noticed....there's no mention of an actor.

That's because the same TinCan support inside of Storyline's xAPI output that allows us to send statements to the launching LMS also allows us to automatically associate the active learner as the actor. So unless we want to override that value with a static value of some sort, we can leave the actor off our custom statements.

What we *are* sending are the other two parts - the verb, and the object. So now if you look back at our code, you can assume that the LMS is going to log this as:

(Active Learner) answered Spectacular

But again - there's more there - what's with the URLs!? If we just want the record to indicate that the learner answered spectacular, why do we have URLs from two different domains, and please tell me I don't have to build a webpage for each value I want to store because honestly I don't have the time for that.

It's ok - take a deep breath. 

Let's start with the verb. The id contains a URL on the adlnet.gov domain, and if you were to visit it in your browser, you would get a 404 error. So again, what's the point?

The point is, by xAPI specifications, the id field must be a URL. For the verb, it does not need to be a unique URL, so in order to make things easy on ourselves, it is best practice to consult [http://xapi.vocab.pub/verbs/index.html](http://xapi.vocab.pub/verbs/index.html) - the go-to resource for ensuring consistent use of verbs. The great thing is, they also give you the URL for each verb, and a description of how that verb is used within the specification.

Consistent verb use? How the verb is used? Isn't a verb just a verb?

Yes and no. 

You can imagine that using verbs provides a lot of added context, but it can also get somewhat confusing - some verbs may mean slightly different things in different uses - for instance, one person might think that "evaluated" is a perfectly good verb for describing someone looking at an object and giving it a financial value. Someone else might think "assessed" is a suitable verb. Grammatically, neither is glaringly wrong, but in the terms of xAPI, both should have used the verb "appraised".

You don't actually have to include anything else after the id, if you don't mind your log showing a long URL as the verb, but if you like a clean, easy to read log, throw on the "display" field to assign how that verb displays in your LMS. 

Object time.

Just like the verb, xAPI requires your object id to be a url, but unlike the verb, this URL needs to be unique. For that reason, it is recommended to replace the "aURLofYOURchoice" portion with a URL you own or have access to, and to create a system for ensuring unique URLs for each activity. You don't need to put a page at that path - you don't need to do anything with it - it just needs to be a URL and it needs to be unique. 

One way I keep up with this is to categorize them by course, then activity, then the specific object itself. This makes it pretty easy to keep things unique, but it also never hurts to keep a log somewhere, just to keep track.

Just as we did with the verb, we're going to give the LMS something a little cleaner to log than a long URL, but as you can see from the code, we aren't using "display" - instead we use "definition" and "name".

We've now added everything needed, as well as a couple of extra pieces to help us out once we move on to interpreting our data, so execute the javascript from a trigger inside your Storyline course, publish the course as Tin Can API, load it up in an xAPI compatible LMS (again, this works great in SCORM Cloud and also Talent LMS, confirmed) and you should be all set up!