Why is the SCORM score not showing in the LMS?
A SCORM score not showing in the LMS almost always means one of four things: the score was written after a status the platform had already locked, the element name does not exist in the version you built, min and max were never set, or no commit landed before the session ended. All four are visible in the runtime log.
The symptom varies by platform: a blank score column, a dash, or 0 for everyone. Often the course itself shows "You scored 84%" on its own results page while the LMS record stays empty — proof the number existed in the browser and never survived the trip to the server. A score that appears for some learners and not others points at timing rather than at the package.
First, check whether the completion status was recorded. If the attempt carries no status and no learner data at all, the problem is not the score — the session never initialised, and the diagnostic checklist for a package that is not working in the LMS is where to start. If only the score is missing, carry on here.
One more early check: relaunching a course you already finished usually opens the attempt in review mode, where the LMS may discard data model writes entirely. Test with a fresh attempt or a fresh test learner.
Status written before score
Some LMSs finalise the attempt record the moment they first see a terminal status — completed, passed, or failed. After that point the API keeps returning "true" to every write, because the API is a courteous liar, but the values are dropped instead of stored. A course that reports completion and then reports the score writes the score into a record that has already closed.
The fix is ordering. Write the numbers first and the verdict last:
SetValue("cmi.score.min", "0") → "true"
SetValue("cmi.score.max", "100") → "true"
SetValue("cmi.score.raw", "84") → "true"
SetValue("cmi.score.scaled", "0.84") → "true"
SetValue("cmi.success_status", "passed") → "true"
SetValue("cmi.completion_status","completed")
Commit("") → "true"
Terminate("") → "true"
Score, then success, then completion, then commit. The same rule applies in SCORM 1.2 with cmi.core.score.* and the single cmi.core.lesson_status field. Because 1.2 collapses "did they finish" and "did they pass" into that one field, a premature passed closes the record for the score as well — the split between the two ideas, and what it costs you, is covered in completion status vs success status.
The wrong score element for the version
SCORM 1.2 and SCORM 2004 do not name the score elements the same way, and neither version accepts the other's names. Writing a 2004 element into a 1.2 package, or the reverse, produces an error and no stored value.
| What you want to store | SCORM 1.2 | SCORM 2004 |
|---|---|---|
| The raw number | cmi.core.score.raw | cmi.score.raw |
| Lowest possible | cmi.core.score.min | cmi.score.min |
| Highest possible | cmi.core.score.max | cmi.score.max |
| Normalised fraction | Does not exist | cmi.score.scaled |
| Pass threshold | cmi.student_data.mastery_score (read-only) | cmi.scaled_passing_score (read-only) |
When the name is wrong, SCORM 1.2 returns error 401, not implemented. SCORM 2004 returns 401, undefined data model element, or 402 when the element is defined in the specification but unimplemented on that platform. Either way the call returns "false" and nothing is stored, so the log tells you immediately if you look at the return value rather than assuming.
Value formatting fails just as quietly. Every value in the data model is a string, but it must be a string the type accepts. "84%", "84/100", and "eighty-four" are all rejected — SCORM 1.2 answers with 405, incorrect data type, and SCORM 2004 with 406, type mismatch. A scaled value outside its permitted range comes back as 407, out of range. The full call-and-error mechanics are in the SCORM API explained.
cmi.score.scaled is a fraction, not a percentage. The permitted range is -1 to 1, so 84% is "0.84". Writing "84" is out of range on a strict platform and, on a lenient one, stores a number the gradebook renders as 8400%.Missing min and max
A raw score on its own is a number without a scale. The LMS has no way to know whether 42 out of a possible 50 is good news unless the package says what the possible range was, and most report columns are rendered as a percentage computed from (raw - min) / (max - min).
Platforms handle the gap in three incompatible ways. Some show the raw number as if it were already a percentage, turning a 42-out-of-50 pass into a 42% fail. Some leave the cell blank rather than guess — the "score not showing" you came here for. Some assume a 0 to 100 range that may not match the assessment.
Two version-specific traps follow from this:
- SCORM 2004 rollup uses
cmi.score.scaled. If the content writes onlyrawand neverscaled, the value can be stored correctly at the SCO level and still leave the gradebook column empty, because the column is fed by the scaled value the rollup expects. - SCORM 1.2 pass or fail can hinge on the scale. Where a course does not set the status itself, some platforms compare the raw score against
cmi.student_data.mastery_scoreand setlesson_statusfrom the result. Feed that comparison an unscaled raw number and it decides the wrong way round.
Write min and max in the same block as raw, every time. It costs two calls and removes an entire class of reporting argument.
The commit never landed
Nothing the content sets is durable until the LMS persists it. Commit is the request to do that, and Terminate is supposed to trigger the same persistence on the way out, but neither helps if the session ends before it runs. The usual endings:
- The learner closes the tab after seeing the results page. No
Terminate, no implicit persist, and whatever the course was holding in the data model dies with the window. - The course commits from an unload handler. Unload events fire late, are unreliable on desktop and routinely cancelled on mobile, so the request is abandoned mid-flight.
- Commit throttling. Some platforms honour one commit every few seconds and drop the rest. A course that fires several commits in the last second of the session can have the one carrying the score discarded.
- Writes after
Terminate. Anything set after the session is closed is invalid — SCORM 2004 answers133, store data after termination — and a results screen that computes and writes the score after the exit call is a common way to produce exactly that.
Commit the score at the moment it is known: min, max, raw, scaled, then the statuses, then a single Commit, with a moment of headroom before Terminate. Test it by finishing the course and closing the tab abruptly instead of clicking the course's own exit button. If the score survives that, it will survive a real learner.
Verifying score in the runtime log
Every cause above is a specific line in a log of the runtime calls the package made. With the arguments, the return values, and the error codes in front of you, work through this order and the answer usually arrives within a minute:
- Is there a
SetValuefor a score element at all? If not, the content never calculated or never attempted to report it, and this is an authoring problem rather than an LMS one. - Does that call return
"true"? A"false"with401means the element name is wrong for the version;405or406means the value was not a valid number;407means it was out of range. - Are min and max set, and are they set before or with raw? Their absence explains a blank or nonsensical percentage even when raw stored cleanly.
- On SCORM 2004, is
cmi.score.scaledset? Rollup and most gradebook columns read it, and raw alone will not populate them. - Does any status write come before the score writes? If
completedorpassedappears above the score in the log, assume the record was locked and reorder the content. - Is there a
Commitafter the score that returns"true"? If the only persistence is the implicit one insideTerminate, any abrupt exit loses the score. - Is
Terminatethe last entry? Anything after it was discarded, whatever it returned.
Run that check before the package goes near a learner, and again against the destination platform: how aggressively an LMS throttles commits, and how early it locks an attempt record, varies far more than the specification suggests.
Where SCORM Central fits
SCORM Central converts files you already have — PDF, PowerPoint, Word, or video — into SCORM 1.2, SCORM 2004, cmi5, or xAPI, and shows you the manifest, the full runtime log, and a conformance report on every build, so you can see exactly what a package will report before an LMS does. See how it works, or start with one file.