Why "it opened on my machine" is not a test
Opening index.html from the unzipped package proves the content renders. It proves nothing about SCORM, because there is no API object to find, so the content either fails silently or runs in a fallback mode that never writes a value. The failures that matter — a manifest the LMS rejects, a bookmark that never saves, a completion that arrives too late — only show up with an LMS-like player that exposes the API and records every call. Test in one of those, every time, before upload.
Step 1: validate the manifest
The LMS reads imsmanifest.xml before it does anything else, and a large share of import failures stop here. Validate it against the schema it declares. The errors that come up most:
- The manifest is not at the root of the zip (it is inside a folder because the zip was made from a parent directory).
- A resource
hrefpoints to a file that is not in the package, or the case differs (Index.htmlvsindex.html— fine on Windows, fatal on Linux-hosted LMSs). - Missing or duplicate
identifierattributes. - A SCORM 2004 package declared with SCORM 1.2 namespaces, or the reverse.
- Sequencing rules that reference an item that does not exist.
A validator that reports these in plain language, with the line number, turns a half-day of guessing into a two-minute fix.
Step 2: launch and watch the runtime log
Launch the package in a test player and read the calls as they happen. A healthy first launch looks like this:
00:00.04 Initialize("") → "true"
00:00.06 GetValue("cmi.learner_name") → "Test Learner"
00:00.07 GetValue("cmi.entry") → "ab-initio"
00:00.09 GetValue("cmi.suspend_data") → ""
00:04.51 SetValue("cmi.location","p2") → "true"
00:04.52 Commit("") → "true"
What you are looking for: Initialize is called exactly once and returns true; the content reads entry and suspend data before writing anything; and a SetValue for location or suspend data appears when you move to the second page. If nothing is written as you navigate, the course will not bookmark. If Initialize is called twice, some LMSs will reject the second call and the session falls apart.
Step 3: resume, then finish
Close the content partway through. Reopen it. Confirm that cmi.entry now returns "resume", that the content reads its suspend data and actually lands on the page you left, and that it did not reset your progress. Then go to the end and complete whatever the course defines as finished. You want to see the status values written, a final Commit, and a single Terminate — in that order, and before the window closes. A course that writes completion and then closes the window without committing will work on forgiving LMSs and lose completions on strict ones. This is the mechanism behind most "lost completion" tickets; Why SCORM completions go missing goes through the rest.
Step 4: check the order of score and status
Some LMSs treat the first arrival of completed or passed as final and ignore later writes to the same attempt. If the content sets status first and score second, those platforms record a pass with no score. The correct order is score, then success, then completion, then commit:
SetValue("cmi.score.scaled", "0.84")
SetValue("cmi.success_status", "passed")
SetValue("cmi.completion_status", "completed")
Commit("")
A conformance report should flag this ordering explicitly; it is cheap to check and expensive to discover in production.
Step 5: replay against the target platform
Every LMS implements the runtime slightly differently. Some throttle Commit to once every few seconds and drop calls in between. Some enforce the suspend-data limit strictly; others silently truncate; a few ignore it. Some reject unknown data model elements; others accept anything. A package that passes the generic player can still fail on the customer's platform because of these differences.
The practical answer is a saved profile per platform: a set of runtime behaviours — commit cadence, suspend ceiling, strictness on unknown elements, how a missing score is handled — that the test player applies when replaying your session. Running the same registration against the Moodle profile and then the SuccessFactors profile shows you which behaviours the package depends on. A passing profile means the package behaved correctly under those conditions; it is not a vendor certification and should not be described as one. SCORM Central ships profiles for the common platforms and lets you run a registration against each.
A checklist you can paste into a ticket
- Manifest at zip root; validates against declared schema; all hrefs resolve with matching case.
- First launch: one
Initialize, entry isab-initio, suspend data empty. - Navigation writes location and/or suspend data, followed by
Commit. - Suspend data stays under the cap (4 KB for 1.2, 64 KB for 2004) with headroom.
- Close and reopen: entry is
resume, content lands on the saved page. - Completion is set exactly when the documented rule says, not earlier.
- Order at the end: score → success → completion →
Commit→Terminate. - Replayed against the target platform's profile with no failures, and any warnings understood.
Attach the runtime log and the conformance report to the delivery. When the customer's administrator asks why a learner shows incomplete, you will have the evidence rather than a theory.