RESOURCE: Full Guide to xAPI and Storyline

Mar 17, 2020

Hello lovely Articulate Storyline users!

I've been working on an in-depth guide to sending custom xAPI statements from Articulate Storyline courses for over a year now, and the full guide is finally complete.

The guide covers everything from writing your first statement to building custom xAPI-powered leaderboards. It also covers a whole lot inbetween, such as collecting quiz responses, measuring time spent on slide, collecting open text responses, and much more.

You can find the full guide here:

If you run into any difficulties or have any questions, please post them here and I will do my best to assist!

25 Replies
Lesley Condon

Wow this is awesome! Before i start to get too excited and/or confused, would this work for when i want to export assessment information into an excel document or google sheet? 

I've been trying to find a solution to gather information on what answers my students are giving in assessments to help understand what topics they struggle in. Will your solution work for this? 



Devlin Peck

Hi Lesley! It absolutely would...I'm actually working on a project now where I automatically send statements from Watershed LRS to a Google Sheet. 

You may want to take a look at Zapier's pricing (an automation tool needed to get the data from the Learning Record Store, or LRS, to a Google Sheet) to see if it fits with your needs / budget.

EDIT: To follow up on this, if you just want to do a basic manual export from LRS to spreadsheet, then you can do that for free from any LRS!

Fiona Macelli

Hi Devlin! Thanks so much for posting these tutorials! I've followed the basic ones backward and forward but am running into a snag because I'm trying to apply what you've written to a different use case. 

1. I would like to use the TinCan compatible LMS "LearnUpon", not a standalone LRS like you've shown. My understanding is that the LMS will supply the "actor" information. I'm not sure if I still need to call GetPlayer() somewhere or not.

2. I would like to use Storyline's default ability to create statements for graded questions and then integrate them with my own statements. I'm hoping to load the whole zip package into the LMS and have it produce one report that contains both default and custom activity statements. From my testing, when I publish a storyline course using TinCan, Storyline produces a file called tincan.xml. The rules of this output are published here.  I believe (but am not certain) that the purpose of this file is the same as the script called xapi-statement.js in your tutorials. The LearnUpon LMS looks for the tincan.xml file in the root folder and won't publish without it. In the tutorial files you've published as Web, not as TinCan. Why is that?

Do you know how I might adapt all the good information in your tutorials to somehow have the javascript triggers execute an activity statement that ends up in the tincan.xml file? Or, is there another approach I could use with an LMS?

Devlin Peck

Hi Fiona! What you're trying to do is definitely possible, but I have not worked with LearnUpon before. Here is the general approach to accomplishing your goal:

  1. Create the xapi-statement.js file just as described in the tutorials, then add the "Execute JavaScript" triggers in your course to generate the custom statements.
  2. Once you've published the xAPI package, connect the story.html file to the xapi-statement.js and xapiwrapper.min.js files, just as described in the tutorials.
  3. The actor information will likely be provided by the LMS via a query string when you launch the course from the LMS. This means that you will need to pull the the actor object from the query string using JavaScript to use it in your custom xAPI statements. (So you will need to modify the xapi-statement.js file accordingly). 
  4. Make sure that the credentials for the conf object are pointing at the LRS that's built into your LMS. If these credentials are not exposed, then I'm not sure how you would send custom statements to their LRS.

You won't need to get user name or email variables from the Storyline course since they'll be provided via a query string by the LMS, but if you want to use any variables from Storyline in your xAPI statements, then you will need to define the player variable using GetPlayer(). This will make more sense once you get to the intermediate tutorials.

After you take a look at query strings and how to access objects from them, give me a shout if you still need a hand. Learning more about JavaScript and xAPI will only help when it comes to accomplishing something like this.

Finally, to answer your question about why I don't publish as an xAPI package -- I prefer to have full control over the xAPI statements that are generated from the course. You cannot modify the verbs used by the default Storyline xAPI functionality (for example, every time a user views a slide, they "experienced" it). This has implications when it comes to querying the data and viewing data streams from multiple tools.

If you aren't too concerned about querying and making the data interoperable with other tools, then it's perfectly fine to do what you're trying to do (and I've done it before myself, too). Perhaps this is a good tutorial to add in the future.

Best of luck!

Fiona Macelli

Thanks so much Devlin, you are clearly the smartest person I know right now lol!  So, do I leave the tincan.xml file as it is, and then the LMS will pull both somehow and integrate the custom statements with the default statements?  Any idea how I'd let the LMS "know" that there is this extra xapi-statement.js to read and report on? I guess the idea is that the script will get launched when the story.html file plays, but how does the LMS "know" to look for stuff to report on if it's outside of the tincan.xml? 

Devlin Peck

Hey again, Fiona. You won't need to deal with the tincan.xml file. The LRS is what receives the statements, and the LMS is what hosts the content. In your case, you will need to send the statements to your LMS's built-in LRS.

You can ensure that those statements get to the LRS by setting the conf object with the endpoint, API key, and API secret, as defined in the tutorials. The story.html file knows that those extra scripts are there because you link them after publishing the course (described in part 3 of the tutorial).

Hope that helps!

Helen Gilbert

Hiya, I'm dipping my toes into xAPI as we're looking at different LMS/LXP.

Looking at your guide has me a little bit worried as it seems so much additional work. With xAPI do you have to build a JSON object for every interaction?

As a minimum we don't want to lose any reporting function we currently have with SCORM 2004, (report on what questions people have answered and if they've got it right or not.) I know xAPI can record so much more, but do you have to manually build that in the JSON file even when using storyline? 

 Any help would be great 

Devlin Peck

Hi Helen,

Storyline does have default xAPI output, but you will get a TON of statements (“User experienced Slide Name” every time the user views a slide, for example). 

The custom approach gives you full control over which statements you send and how to send them. It takes a bit of up-front work to build the JavaScript function(s), but once you do that, you just need to add execute JavaScript triggers with one line of JavaScript in them that tell the function which elements to include. 

So no, you only need to build the JSON objects once (or a few times if you need to structure your statements differently depending on the use case). When it comes to sending the statements from Storyline, it’s as simple as an execute JavaScript trigger that passes the correct elements into the function. 

That might sound confusing if you’re brand new to JavaScript, but I’m happy to answer any other questions to clear things up!

Aaron Kapala

Hi Devlin,

Thanks for putting all this together, it’s amazing and so helpful when working with custom statements.

Would I be right in guessing if we sent a variable text entry in say Module 1 as a statement to the LRS,  we would be able to pull that statement into Module 2 so the user could see their entry to continue the user journey?

If so, I don’t suppose you have any tutorials on that?

Thanks again for all your work you’ve put into the tutorials above.

Devlin Peck

Hi Aaron,

You're welcome! That is possible (see the "advanced" section of the full guide), but it would not be super secure if you're doing this on the open web. The reason for this is because the LRS would need to have "read" permissions turned on, which means that someone would be able to query all of your data if they were tech-savvy enough to do so.

If your content is already gated behind an LMS login, then it may be a tad safer to do so (since it would be your employees who get access to the code / credentials).

If I were to implement this today, I would use the xAPI Document APIs (which I just recently started using and do not have tutorials up for yet) or a simple database like Firebase Firestore (with Firebase Auth along with it to keep things secure).

Best of luck,

Aaron Kapala

HI Devlin,

Thanks for your response, it's great to know it can be done - I will do some testing as the LRS I am using is just for testing purposes so no real data but if it all works then I will look at testing it with our own LMS/LRS system in-house.

Thanks again for all your help.


Jason Haag

Hi Everyone,

Veracity Learning ( recently added hosting options to their LRS as well. So if you don't have an LMS and you also don't have a web server to host your content, this is a simple and affordable alternative. It also provides a way for you to add learners and a login capability that you would normally expect in an LMS.

I recently posted a tutorial on how to use this feature (if you're interested):



Jack Jones

Hi Devlin,

I followed the How to collect quiz scores tutorial to the letter.  I published it as xAPI and changed the Story.html to include the Wrapper.js and the statement.js files and included both of the files in the root of the file.  I then zipped the package.  I am still not getting the answers.  I am only getting “User experienced Slide Name.  Any ideas?

Paul Kizilos

Hi Devlin,

Great work on the guide. For others who are working on xAPI in Storyline, you can include the tincan-min.js file in a web object that is then automatically imported to the published package. Add the  JS file in the same folder as the HTML. Add the JS to the HTML as an "object" - <object>...</object> (not as a script) to a non-displaying slide. This forces the web object builder to include the JS file. You can then add the JS file to a master slide where you need it by creating the "script" DOM element and attaching it to the document. That is done through custom javascript on the slide master. The script can then be referenced by your xAPI custom javascript on the slides that use that master slide.

Why do it this way? Because the tincan-min.js file is too large to just include in a custom javascript object directly in Storyline. It also means you don't have to manually modify the story.html file. Works great if you publish a Storyline interaction directly to Review 360 and then include it in a Rise document.

I just wanted to thank you - and credit you. You've helped me. Thanks!

Sarah Dale

Hi Devlin, 

I'm looking for a solution where our vendors/suppliers can "share" their e-learning courses with us to distribute through our LMS where we both have access to reporting (without them having access to our LMS, or us having their SCORM files).  Would xAPI be a potential solution to this? Can it be shared via a link/URL?



Marcelo Appezato

Hi Devlin. I´m trying to figure out if it would be possible to gather comments made during the creation of a training material on Articulate (not by the end user of the material). I couldn´t find any actions related to that, but the final idea would be to capture these comments and add them to a BPM software that is managing the creation process of the material through an iPaaS (similar to Zapier).

Stephen Wilhite
Paul Kizilos

Works great if you publish a Storyline interaction directly to Review 360 and then include it in a Rise document.

Paul, honestly most of what you wrote is out of my current depth, but this statement stood out as it's one of the thorny issues we'll be dealing with as we implement xAPI. Would you happen to have any samples of this approach you could share, or perhaps touch base offline?

Stephen Wilhite

Devlin, first of all, kudos on the tutorials, they're awesome! I wanted you to know that I was able to adapt them to be able to pull the Student ID from a non-xAPI compliant LMS and send that as the Actor to the LRS, which is one of our requirements. Worked like a charm!

My question is have you played around any more with the built-in Storyline LRS tracking features? One of the issues we encountered early on (and I believe you also called out in one of your videos) was the fact that you couldn't easily add Actor information when publishing for SCORM. There does appear to be a way to do that now, but it only seems to work when hard coding the value for the "name" parameter, where what I'd like to do is replicate what I did with your tutorial and grab the Student ID from the LMS.

Any thoughts?

Stephen Wilhite

Hi Sarah,

This doesn't sound like a scenario where xAPI would fit the bill, but I do know that it's a fairly common one that products like SCORM Cloud Dispatch or Content Controller could help with. More info here: