SCORM score not showing in the LMS

SCORM score not showing in the LMS? Four causes: status written before score, the wrong element for your version, missing min and max, no commit.

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 storeSCORM 1.2SCORM 2004
The raw numbercmi.core.score.rawcmi.score.raw
Lowest possiblecmi.core.score.mincmi.score.min
Highest possiblecmi.core.score.maxcmi.score.max
Normalised fractionDoes not existcmi.score.scaled
Pass thresholdcmi.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 only raw and never scaled, 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_score and set lesson_status from 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 answers 133, 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:

  1. Is there a SetValue for 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.
  2. Does that call return "true"? A "false" with 401 means the element name is wrong for the version; 405 or 406 means the value was not a valid number; 407 means it was out of range.
  3. 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.
  4. On SCORM 2004, is cmi.score.scaled set? Rollup and most gradebook columns read it, and raw alone will not populate them.
  5. Does any status write come before the score writes? If completed or passed appears above the score in the log, assume the record was locked and reorder the content.
  6. Is there a Commit after the score that returns "true"? If the only persistence is the implicit one inside Terminate, any abrupt exit loses the score.
  7. Is Terminate the 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.

Keep reading

How-to4 min Convert SCORM to video or PowerPoint? Can you convert SCORM to MP4, HTML5 or PowerPoint? What is inside a package, the routes that work, and what you lose with each one. Explainer4 min Does your LMS support xAPI? How to check What xAPI LMS support really means: launching xAPI content, a built-in LRS, or forwarding statements. The questions to ask and a quick test to run. Explainer4 min LMS vs LRS: what is the difference? LMS vs LRS: an LMS runs courses and learners; an LRS stores xAPI statements. Why SCORM does not use an LRS, and when you need both.

Start with one file.

Upload something you already have and see it as a package, with the conformance report and the runtime log alongside it.

→ upload  handbook.pdf
  parsing … 14 sections
  building manifest …
  validating … 0 errors, 2 notes
✓ handbook-scorm2004.zip
✓ preview link ready