Can you show storyline quiz score as a percentage?

Oct 03, 2023

We've build a game show quiz with Articulate Storyline with 3 stages, 5 question in each stage with a total of 15 questions. For every correct answer, the user gets 100 point and the aim of the course is to get as much of a high score as possible. We are having issue reporting the course/quiz on the LMS we are using. We  tried to run a report on our LMS to report on percentage using the field 'SCORM 2004 Quiz Data - Quiz score' but its not showing the correct percentage score. For example, one result was 1400 points (14/15) so the percentage score should show 93% but its shows 33%. Below is a screenshot showing this:

LMS Report  All the relevant quiz setting have been selected to score on, we have a 'submit score' trigger on the final slide when the timeline starts. Is there anything we are missing that is causing the score to show incorrectly.

2 Replies
Jose Tansengco

Hi Nathan, 

Happy to help!

Can I ask if you've tested the behavior on a different LMS to see if the scoring issue is specific to your LMS? If you haven't yet, here's a helpful article on testing courses in SCORM Cloud

If you are able to replicate the scoring issue in SCORM Cloud, would you be willing to share a copy of your project file here or in private by opening a support case so we can take a closer look at what's happening? We'll delete it when we're done testing!

Scott Maxwell

You can do this using JavaScript and xAPI statements and queries. 

I'll show you the code I use.

 // Sends the users' answer choices and results */
function sendAnswered(object, objectId, responseVar, success) {
    const player = GetPlayer();
    const uNamejs = player.GetVar("uName");
    const uEmailjs = player.GetVar("uEmail");
    const userResponse = player.GetVar(responseVar);
    const uScorejs = player.GetVar("uScore");
    const maxScorejs = player.GetVar("maxScore");
    const scaledScore = uScorejs / maxScorejs;
    let finalDuration = convertToIso(slideSeconds);

    const statement = {
        "actor": {  
            "name": uNamejs,
            "mbox": "mailto:" + uEmailjs
        },
        "verb": {
            "id": "http://adlnet.gov/expapi/verbs/answered",
            "display": {"en-us": "answered"}
        },
        "object": {
            "id": objectId,
            "definition": {
                "name": {"en-us": object},
                "description": {"en-us": "Question in the Quiz"},
                "type": "http://adlnet.gov/expapi/activities/question"
             },
             "objectType": "Activity"
        },
        "result": {
            "duration": finalDuration,
            "response": userResponse,
            "score": {
                "min": 0,
                "max": maxScorejs,
                "raw": uScorejs,
                "scaled": scaledScore
            },
            "success": success
        }
    }
    const result = ADL.XAPIWrapper.sendStatement(statement);
}

// Function to send passed result and user score to the LRS (Learning Record Store)
function sendPassed(object, objectId) {

// Get references to Storyline variables
  const player = GetPlayer();
  const uNamejs = player.GetVar("uName");
  const uEmailjs = player.GetVar("uEmail");
  const uScorejs = player.GetVar("uScore");
  const maxScorejs = player.GetVar("maxScore");
  const scaledScore = uScorejs / maxScorejs;

  // Format the course duration as ISO 8601
  let finalDuration = convertToIso(courseSeconds);

  // Define the xAPI statement to send
  const statement = {
    "actor": {  
      "name": uNamejs,
      "mbox": "mailto:" + uEmailjs
    },
    "verb": {
      "id": "http://adlnet.gov/expapi/verbs/passed",
      "display": {"en-us": "passed"}
    },
    "object": {
      "id": objectId,
      "definition": {
        "name": {"en-us": object},
        "description": {"en-us": "NGTS Network Overview"},
        "type": "http://adlnet.gov/expapi/activities/assessment"
      },
      "objectType": "Activity"
    },
    "result": {
      "duration": finalDuration,
      "score": {
        "min": 0,
        "max": maxScorejs,
        "raw": uScorejs,
        "scaled": scaledScore
      },
      "success": true
    }
  };

// Converts the time to ISO standard readable in JavaScript 
function convertToIso(secondsVar) {
    let seconds = secondsVar;
    if (seconds > 60) {
      if (seconds > 3600) {
        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        seconds = (seconds % 3600) % 60;
        return `PT${hours}H${minutes}M${seconds}S`;
      } else {
        const minutes = Math.floor(seconds / 60);
        seconds %= 60;
        return `PT${minutes}M${seconds}S`;
      }
    } else {
      return `PT${seconds}S`;
    }
  }  
 
 
Then you would want some placeholders within your storyline file for the usernames and scores.

firsUser and firstScore

These are pretty typically used placeholders after Devlin Peck published how to develop a leaderboard using xAPI.  So, I'll use his example in this reference so you can follow along with his instructions if you get stuck.

I have added to the code to include debugging to help you find any errors when viewing the console log (F12 when you are viewing the exported html).
// Function to populate Storyline leaderboard using the project variables for users and scores
function populateLeaderboard() {
  // Create parameters for querying xAPI statements
  const parameters = ADL.XAPIWrapper.searchParams();
  parameters["verb"] = "http://adlnet.gov/expapi/verbs/passed";
  parameters["activity"] = "http://example.com/NGTSNetworkOverview";
 
  // Query the LRS for xAPI statements
  const queryData = ADL.XAPIWrapper.getStatements(parameters);
 
  // Sort the statements by scaled score in descending order
  const statements = queryData.statements;
  statements.sort(function(a, b) {
    return b.result.score.scaled - a.result.score.scaled;
  });

  // Update Storyline Player Project Variables with sorted user names and scores as percentages
  const player = GetPlayer();
  player.SetVar("firstUser", statements[0].actor.name);
  player.SetVar("secondUser", statements[1].actor.name);
  player.SetVar("thirdUser", statements[2].actor.name);
  player.SetVar("fourthUser", statements[3].actor.name);
  player.SetVar("fifthUser", statements[4].actor.name);

  // Debugging: Log the scaled scores and user scores as percentages
  console.log("Scaled Scores:", statements.map((stmt) => stmt.result.score.scaled));
  console.log("User Scores (Percentages):", statements.map((stmt) => stmt.result.score.scaled * 100 + "%"));

  // Set user scores as percentages in Storyline variables
  player.SetVar("firstScore", statements[0].result.score.scaled * 100 + "%");
  player.SetVar("secondScore", statements[1].result.score.scaled * 100 + "%");
  player.SetVar("thirdScore", statements[2].result.score.scaled * 100 + "%");
  player.SetVar("fourthScore", statements[3].result.score.scaled * 100 + "%");
  player.SetVar("fifthScore", statements[4].result.score.scaled * 100 + "%");
}
Please let me know if this helped you or not. Happy to chat about it via LinkedIn when you have time. 

Scott