How to access xAPI/Tin Can LMS variables in JavaScript

Dec 06, 2018

When Storyline 360 publishes a SCORM 1.2 or 2004 package, an entire library of SCORM JavaScript functions are created and can be used inside Storyline (for instance: SCORM_CallLMSGetValue("cmi.core.student_id") will get you the student ID from the LMS). Similarly you can use lmsAPI.GetStudentName() (after initializing the lmsAPI variable, of course) to get the student name from the LMS.

When publishing an xAPI package, there does not appear to be such libraries published, or the functions are much less clear. How would I go about getting the xAPI equivalents of SCORM_CallLMSGetValue("cmi.core.student_id") and lmsAPI.GetStudentName()? I can't seem to find any documentation on this anywhere.

27 Replies
Nandhakumar S

Here is Retrieve the username From storyline code.

function getParameterByName(name, url) {

if (!url) url = window.location.href;

name = name.replace(/[\[\]]/g, "\\$&");

var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),

results = regex.exec(url);

if (!results) return null;

if (!results[2]) return '';

return decodeURIComponent(results[2].replace(/\+/g, " "));

}

var a =[];var a1 = [];

var foo = getParameterByName('actor');

a = foo.split(",");

var x=a[0];

a1 = x.split(":");

var str = a1[1];

var UName = str.replace(/[^a-zA-Z ]/g, "");

var player = GetPlayer();

player.SetVar("UserName",UName);

Scott Dellinger

Thanks for the info! I actually figured out that I could get the actor info from the querystring and parsed it all together, however, I'd still like to be able to interact with the LMS variables not available in the querystring, such as the completion status and score. Is there no way to do this in Storyline 360 if you're using Tin Can?

Scott Dellinger

This ended up working for me (this is the "passed" version... I also have a failed version):

var player = GetPlayer();
var iascore = { raw: player.GetVar("FinalPercent"),min:0,max:100 };
var iatc = new TinCan({url: window.location.href});
var stmt = { verb: "passed", inProgress: false, result: { } };
stmt.result.success = true;
stmt.result.score = iascore;
iatc.sendStatement(stmt);

I used a custom variable in Storyline called "FinalPercent" to obtain the Results.ScorePercent and report it back to the LMS.

Nandhakumar S

You can use this code for failed version.

var player = GetPlayer();
var iascore = { raw: player.GetVar("FinalPercent"),min:0,max:100 };
var iatc = new TinCan({url: window.location.href});
var stmt = { verb: "failed", inProgress: false, result: { } };
stmt.result.success = false;
stmt.result.score = iascore;
iatc.sendStatement(stmt);

Kimberly Bold

Can you guys please tell me where you're entering your code?  What file(s)?  I followed the instructions from this example which required updating the Story_html5.html file with the insertion of some test js files that were also provided in the instructions, but would like to know how to execute without the override.  I'm also looking for guidance on the Javascript statement in Storyline to include multiple variables/statements as the above example only included one Verb.  I'm new to xAPI as well as JavaScript, so any assistance is greatly appreciated.  Thanks in advance!!

Steven Pascoe

Hi, can anyone help me? Nandhakumar S code doesn't work quite right.

The Tin Can code works on Scorm Cloud but not on our custom system. We get mailto

Is there any workaround?

This might be occuring because of mbox.

mailto

function getParameterByName(name, url)
{
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
var a =[];var a1 = [];
var foo = getParameterByName('actor');
a = foo.split(",");
var x=a[0];
a1 = x.split(":");
var str = a1[1];

var UName = str.replace(/[^a-zA-Z ]/g, "");

var player = GetPlayer();
player.SetVar("Username",UName);

 

Appreciated!

Rosy Colelli

Hello, I need to pass my score to LMS. I have to publish the course as Tincan. I tried the below Java but doesn't work.... LMS shows Score unknown

var player = GetPlayer(); var passingScore = "75"; function findLMSAPI(win) { if (win.hasOwnProperty("GetStudentID")) return win; else if (win.parent == win) return null; else return findLMSAPI(win.parent); } var lmsAPI = findLMSAPI(this); lmsAPI.SetScore(player.GetVar("Score"), 75, 0); if (player.GetVar("Score")>= passingScore) { SetStatus("passed"); } else { SetStatus("failed"); }

 

Could you help me, please?

Rosy Colelli

Hello, I need to pass my score to LMS. I have to publish the course as Tincan. I tried the below Java but doesn't work.... LMS shows Score unknown

var player = GetPlayer(); var passingScore = "75"; function findLMSAPI(win) { if (win.hasOwnProperty("GetStudentID")) return win; else if (win.parent == win) return null; else return findLMSAPI(win.parent); } var lmsAPI = findLMSAPI(this); lmsAPI.SetScore(player.GetVar("Score"), 75, 0); if (player.GetVar("Score")>= passingScore) { SetStatus("passed"); } else { SetStatus("failed"); }

 

Could you help me, please?

Scot Taylor

I am trying to achieve something similar in xAPI. In SCORM I would use the following code to pass score, success status and complete.

var player = GetPlayer();
var passPercent = player.GetVar("passPercent");
var percentScore = player.GetVar("percentScore");
function findLMSAPI(win) {
if (win.hasOwnProperty("GetStudentID")) return win;
else if (win.parent == win) return null;
else return findLMSAPI(win.parent);
}
var lmsAPI = findLMSAPI(this);
lmsAPI.SetScore(percentScore, 100, 0);
if (percentScore >= passPercent){
SCORM2004_CallSetValue("cmi.success_status", "passed");
}else{
SCORM2004_CallSetValue("cmi.success_status", "failed");
}
lmsAPI.SetReachedEnd();


With xAPI I am attempting to use the following code based on above :

var player = GetPlayer();
var passPercent = {raw: player.GetVar("passPercent")};
var percentScore = {raw: player.GetVar("percentScore")};
 var iascore = { raw: player.GetVar("percentScore"),min:0,max:100};
var iatc = new TinCan({url: window.location.href});
var passStmt = { verb: "passed", inProgress: false, result:{ } };
var failStmt = { verb: "failed", inProgress: false, result:{ } };
if (percentScore >= passPercent){
passStmt.result.success = true;
passStmt.result.score = iascore;
iatc.sendStatement(passStmt);
 
}else{
failStmt.result.success= false;
failStmt.result.score = iascore;
iatc.sendStatement(failStmt);
 
}

 

Any idea where I am making a mistake? I would greatly appreciate any insights.

Ben Kanspedos

I have been trying to extract the user's name from the LMS (Docebo). But when it's published to xAPI I can't get it to work.

I tried the code in this thread, and other code, and I always get the console message: "actionator::exeJavaScript - this.execUserJs is not a function"

Scott and Nandhakumar, are you able to retrieve the name when published to xAPI?

 

Robert Webbe

@Ben Kanspedos

I've dived into this topic last week and learned that it's not going to work when published to xAPI. There is a trick: 

1) Publish your project to SCORM (2004)
2) Publish your project again to xAPI
3) Copy the files from the SCORM output to the xAPI output folder (skip duplicates)
4) ZIP the file 

It's a lot more work but it works. I've send a feature request to Articulate for an option to do this in one run.

I've attached my test (story) file for you.

Jürgen Schoenemeyer

here is a short script to parse to xAPI start url for the actor name

function parseName( inURL ){
const urlParams = new URLSearchParams(inURL.split("?")[1]);

var name = "unknown";

if( urlParams.has("actor") ){
var actor = JSON.parse( urlParams.get("actor") )

if( "name" in actor ){
name = actor.name[0];
}
} else {
console.error( "no 'actor' in url: ", urlParams );
}

console.log( "name: " + name );
return name;
}

var url = window.location.href;
var name = parseName( url );
GetPlayer().SetVar("name", name);

this work e.g. on Scorm Cloud

 

Robert Webbe

Wow, that is good news!

As you say, it works perfectly in Scorm Cloud. On our LMS (Stream LXP from Learningpool) it only states the first initial of my first name. I've checked the URL form Scorm Cloud and our LMS and these are the differences:

https://cloud.scorm.com/sandbox/content/courses/NYQLJL20DW/GetLearnersNameFromLMSfd69a70d-fa7b-4a60-a365-c21cd51cc12e/0/index_lms.html?actor=%7B%22name%22%3A%5B%22Robert%20Webbe%22%5D%2C%22account%22%3A%5B%7B%22accountServiceHomePage%22%3A%22http%3A%2F%2Fcloud.scorm.com%22%2C%22accountName%22%3A%22NYQLJL20DW%7Crobert.webbe%40vodafoneziggo.com%22%7D%5D%2C%22objectType%22%3A%22Agent%22%7D&endpoint=https%3A%2F%2Fcloud.scorm.com%2Flrs%2FNYQLJL20DW%2F&auth=Basic%20OjRlNzk1ZTU4LWQ1MDAtNDIyMi04Zjc1LTAyMzJiMWFjYjU0NQ%3D%3D&content_token=a025fb1d-2c75-4851-a658-31ed6ab9564d&externalRegistration=L4dGVbJhbQIJiyF6qq9THUfRi-N54jrZWQRLCtfcWqN0qWCgFYOt5gzGyymZdqPjbNeY93w1-YDaGi7G6PpQC3f1T-6VGlSqiC9LV5nhwfdbgf-CoRgcXqkDtJzNz1s&activity_id=urn%3Aarticulate%3Astoryline%3A5f7Ku7j0hV7&registration=8b731e71-19da-44e2-a1f7-b9b27fc1e493&externalConfiguration=62aEfcbopf-tVvu2eBkxA87cOpHhc5tITFcaJS8wssHNIOjNbQ8Gp9-0fh303END15H_wc2Uq4a3TYtc5pBljilllruO2y-3&grouping=urn%3Aarticulate%3Astoryline%3A5f7Ku7j0hV7&content_endpoint=https%3A%2F%2Fcloud.scorm.com%2Flrs%2FNYQLJL20DW%2Fcontent%2F&width=988&height=744&left=466&top=0

https://content-nlv-eu-central-1.curatr3.com/launcher/index.html?url=https%3A%2F%2Fcontent-nlv-eu-central-1.curatr3.com%2Fresources%2F1762%2Fget-learners-name-from-lms_1687252656%2Findex_lms.html%3Fendpoint%3Dhttps%253A%252F%252Flauncher-curatr.learninglocker.net%252Fcontent%252Flaunch%252F0301bfd8-c319-43d6-9066-7d855bcb6a0b%252FxAPI%252F%26auth%3DBasic%2520LS0tOi0tLQ%253D%253D%26activity_id%3Dhttps%253A%252F%252Fjunkyard.curatr3.com%252Fxapi%252Factivity%252Fresource%252F863792%26actor%3D%257B%2522mbox%2522%253A%2522mailto%253Arobert.webbe%2540vodafoneziggo.com%2522%252C%2522objectType%2522%253A%2522Agent%2522%252C%2522name%2522%253A%2522Robert%2520Webbe%2522%257D%26registration%3D494b54d0-9ed5-4f2d-8a98-7f0bb2dbe12b

My knowledge of this not sufficient to make it work for our LMS. Do you know how I can get it to work? Many thanks in advance! 🙏

Jürgen Schoenemeyer

try

function parseName( inURL ){
var name = "unknown";

var outerParams = inURL.split("?")[1];
var urlParams = new URLSearchParams(outerParams);

var innerParams = urlParams.get("url").split("?")[1]
var urlParamsTwo = new URLSearchParams(innerParams);

if( urlParamsTwo.has("actor") ){
var actor = JSON.parse( urlParamsTwo.get("actor") )

if( "name" in actor ){
name = actor.name;
}
}

console.log( "Name: " + name );
return name;
}

var url = window.location.href;
var name = parseName( url );
GetPlayer().SetVar("name", name);

result: "Name: Robert Webbe"

Jürgen Schoenemeyer

perhaps a variant of my first solution

function parseName( inURL ){
const urlParams = new URLSearchParams(inURL.split("?")[1]);

var name = "unknown";

if( urlParams.has("actor") ){
var actor = JSON.parse( urlParams.get("actor") )

if( "name" in actor ){
name = actor.name;
}
} else {
console.error( "no 'actor' in url: ", urlParams );
}

console.log( "name: " + name );
return name;
}

var url = window.location.href;
var name = parseName( url );
GetPlayer().SetVar("name", name);

name = actor.name; <- without [0]