Getting Started with SCORM: Tracking Course Specific Data

How SCORM Tracks Course Data
Summary: Continuing on in our discussion of the SCORM standard and how communication happens between a SCO and as LMS, in this installment we will be diving a bit into the SCORM data model and discussing how SCORM tracks course data.

We previously discussed how a SCO finds the LMS API, the basics of how to send/retrieve data and touched on the SCORM data model. We are going to build on some of those concepts today and dive into the nuts and bolts of how a SCO uses the SCORM data model to track course data in the real world.

How SCORM Tracks Course Data

If you take the time to read the full SCORM spec and look at the data model (available at: you will notice a long laundry list of available variables that are supported. These variables define the pieces of information a SCO can retrieve from the LMS, or send to the LMS and ask the LMS to store for future use. The great news is that the vast majority of courseware - whether custom built or created using a tool like articulate or captivate - only use a small subset of these variables.

I'm sure when they were writing the spec some of the data model items sounded like great ideas. For example the spec defines "cmi.student_preference.speed" which is supposed to be used by the course to define the speed at which to deliver content to the student. Sounds interesting, but I have yet to see this variable actually used by any course. The data model contains lots of these seldom used variables - and although I'm glad they exist for those off chances when you need them - they do tend to make the data model seem very intimidating to someone just getting started.

Most of the items in the data model have a very specific purpose. For example cmi.score.raw is used to store what the user's relative score on the SCO is. Or cmi.location can be used to store the user’s current location in the SCO (although this is rarely used).

The real work horse of the data model that tracks most course data is the "cmi.suspend_data" variable. This is used by SCOs to store SCO specific data in-between user sessions. So for example if a  SCO wants to store data about what pages a user viewed, what quiz questions they answered right/wrong, or any other general information about the user's interaction with the SCO, it does so by  dumping all that data into suspend_data.

Now this is where SCORM is both wonderful and terrible. The great thing about the concept of suspend data is that you can use it to store almost anything. So regardless of what you want your SCO to track, suspend data will help you get the job done. Now the terrible thing about suspend data is that it’s completely unstructured and simply a long text string…..and every vendor saves their data in a different format.

So what does this look like? Below is an example of suspend_data from an articulate course:


If you look at the string you will notice a couple pieces of text. "viewed=" indicates the part of the string that tracks what slides the user has viewed (separated by commas). "lastviewedslide=" tracks the last slide the user was on when they closed the SCO. Finally the bit long set of numbers separated by a comma tracks the state of the navigation panel in articulate.

Although the format of this data will most definitely change from vendor to vendor, and the content will change from course to course, the concept remains the same. As a user progresses through a SCO it will dump information about their progress into suspend_data. When a user returns to a SCO it will pull their suspend_data from the LMS, parse it, and figure out where they left off, what slides they have viewed, or even what quizzes they have completed.

If you are creating a custom SCORM wrapper, determining how you want to store and parse suspend data is by far one of the biggest technical challenges of the whole endeavor. The secret here is the javascript split function, which basically lets you take a string and split it into an array (for you developers out there we are going to avoid using regular expressions here to keep these examples simple).

So if we use the split function on the data above, and split data the | character we would end up with 3 strings in our array:

#1) viewed=1,2,3

#2) lastviewedslide=3

#3) 2#1##,7,7,11,1,1,1#0,0,0,0,0,0##-1

So if our SCO needed to figure out what slides a user had viewed it would split the suspend_data the first time, grab the first value (since that indicates what slides have been viewed), replace the text "viewed=" (because we know that is a constant that just indicates what the string identifies) and then split the string a second time on the comma character. In which case we end up with:

#1) 1

#2) 2

#3) 3

The course can loop through those values and easily determine what slides have been viewed.

Every time you launch a SCORM compliant course it goes through a similar process. If a user is resuming their progress, it grabs all the user's suspend data for that course, parses it, and then acts appropriately based on where the user left off. When a user goes to close a course, the process works somewhat in reverse and the course will grab all the data it needs regarding the user's progress, shove it into a long string and then call api.LMSSetValue and set the value for the cmi.suspend_data variable.

Out of all the elements in the SCORM data model, cmi.suspend_data is one of the most crucial and most complex to understand. Hopefully this article has helped you understand it a bit more. This topic is a complicated one so if you have any questions please feel free to leave a comment and I’ll do my best to get you answers.