SCORM Package Structure: Complete Technical Reference for LMS Admins, Developers & Instructional Designers (2026)

When a SCORM package silently fails to track completion, imports with no error but launches a blank screen, or shows status “not attempted” after a learner finishes an entire course – the root cause is …

scorm package structure

When a SCORM package silently fails to track completion, imports with no error but launches a blank screen, or shows status “not attempted” after a learner finishes an entire course – the root cause is almost always in the package structure, not the LMS. This guide maps every structural component that governs that behavior, with exact XML markup derived from the ADL SCORM 2004 4th Edition specification (released January 2009) and SCORM 1.2 (October 2001).

The Three Architectural Layers of a SCORM Package

Every SCORM package (formally, a Package Interchange File or PIF) is a ZIP archive operating across three distinct layers. Conflating them is the most common source of debugging dead ends:

Layer Specification Role
Content Packaging IMS Content Packaging + ADL CAM Defines the ZIP structure, imsmanifest.xml, organization hierarchy, and resource declarations
Run-Time Environment IEEE 1484.11.2 (1.2) / 1484.11.1 (2004) JavaScript API between SCO and LMS; data model elements
Sequencing & Navigation IMS Simple Sequencing 1.0 (2004 only) Learner flow rules, rollup, prerequisites – declared in manifest via imsss: namespace

SCORM 1.2 uses layers 1 and 2. SCORM 2004 adds layer 3 and substantially revises layer 2.

Package Structure: The ZIP Architecture

A conformant SCORM PIF unpacks to the following canonical structure:

course-root/

├── imsmanifest.xml ← REQUIRED at root; cannot be in a subfolder

├── SCORM-schemas/ ← XSD/DTD schema definition files

│ ├── imscp_v1p1.xsd

│ ├── adlcp_v1p3.xsd (2004 only)

│ ├── adlseq_v1p3.xsd (2004 only)

│ ├── adlnav_v1p3.xsd (2004 only)

│ └── imsss_v1p0.xsd (2004 only, required for sequencing)

├── shared/ ← Assets shared across SCOs (optional)

│ ├── scormfunctions.js

│ └── style.css

└── module-01/ ← SCO content directory

├── index.html ← Launch file (href in resource element)

├── content.js

└── media/

└── video.mp4

Critical constraint: The imsmanifest.xml must sit at the ZIP root – not inside a folder. An LMS discovers it by looking for imsmanifest.xml at path ./, not ./coursefolder/imsmanifest.xml. This is the single most-reported upload error across Moodle forums, the Articulate community, and the Rustici support knowledge base.

The XSD files are technically optional for LMS import in most implementations, but the ADL specification states that conformant packages should include them. For SCORM 1.2, the required schema set is: imscp_rootv1p1p2.xsd, adlcp_rootv1p2.xsd, ims_xml.xsd, and imsmd_rootv1p2p1.xsd. Download links for all version-specific schema sets are maintained at scorm.com/scorm-explained/technical-scorm/content-packaging/xml-schema-definition-files/.

The imsmanifest.xml: Deep Structure Reference

The manifest is the structural backbone of the package. Its four mandatory top-level children – metadata, organizations, resources, and optionally (sub)manifest – map to the four concerns of course description, activity hierarchy, file inventory, and modular reuse.

SCORM 1.2 Manifest

<?xml version=”1.0″ encoding=”UTF-8″?>

<manifest identifier=”com.company.course.compliance-2026″

version=”1.0″

xmlns=”http://www.imsproject.org/xsd/imscp_rootv1p1p2″

xmlns:adlcp=”http://www.adlnet.org/xsd/adlcp_rootv1p2″

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=”http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd

http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd”>

<metadata>

<schema>ADL SCORM</schema>

<schemaversion>1.2</schemaversion>

</metadata>

<organizations default=”ORG-001″>

<organization identifier=”ORG-001″>

<title>Annual Compliance Training 2026</title>

<item identifier=”ITEM-001″ identifierref=”RES-SCO-001″>

<title>Module 1: Data Privacy</title>

<adlcp:masteryscore>80</adlcp:masteryscore>

<adlcp:maxtimeallowed>PT1H30M</adlcp:maxtimeallowed>

<adlcp:timelimitaction>exit,message</adlcp:timelimitaction>

</item>

<item identifier=”ITEM-002″ identifierref=”RES-SCO-002″>

<title>Module 2: Code of Conduct</title>

<adlcp:masteryscore>80</adlcp:masteryscore>

</item>

</organization>

</organizations>

<resources>

<resource identifier=”RES-SCO-001″

type=”webcontent”

adlcp:scormType=”sco”

href=”module-01/index.html”>

<file href=”module-01/index.html”/>

<file href=”module-01/content.js”/>

<dependency identifierref=”RES-SHARED”/>

</resource>

<resource identifier=”RES-SCO-002″

type=”webcontent”

adlcp:scormType=”sco”

href=”module-02/index.html”>

<file href=”module-02/index.html”/>

<dependency identifierref=”RES-SHARED”/>

</resource>

<resource identifier=”RES-SHARED”

type=”webcontent”

adlcp:scormType=”asset”>

<file href=”shared/scormfunctions.js”/>

<file href=”shared/style.css”/>

</resource>

</resources>

</manifest>

Key structural rules for SCORM 1.2:

  • <schemaversion> must contain exactly 1.2
  • adlcp:scormType is either sco (communicates with the LMS API) or asset (static, no API communication)
  • <adlcp:masteryscore> sets the score threshold (0–100 integer) that determines passed/failed. LMSes that default to treating completed as passing will ignore this unless the SCO explicitly sets cmi.core.lesson_status to passed or failed based on score

SCORM 2004 4th Edition Manifest

The 4th Edition (January 2009) manifest adds three new namespace declarations – adlseq, adlnav, and imsss – and introduces the <adlcp:completionThreshold> element with attribute-based syntax (replacing the 3rd Edition child-element syntax):

<?xml version=”1.0″ encoding=”UTF-8″?>

<manifest identifier=”com.company.course.compliance-2026″

version=”1.0″

xmlns=”http://www.imsglobal.org/xsd/imscp_v1p1″

xmlns:adlcp=”http://www.adlnet.org/xsd/adlcp_v1p3″

xmlns:adlseq=”http://www.adlnet.org/xsd/adlseq_v1p3″

xmlns:adlnav=”http://www.adlnet.org/xsd/adlnav_v1p3″

xmlns:imsss=”http://www.imsglobal.org/xsd/imsss”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=”http://www.imsglobal.org/xsd/imscp_v1p1 SCORM-schemas/imscp_v1p1.xsd

http://www.adlnet.org/xsd/adlcp_v1p3 SCORM-schemas/adlcp_v1p3.xsd

http://www.adlnet.org/xsd/adlseq_v1p3 SCORM-schemas/adlseq_v1p3.xsd

http://www.adlnet.org/xsd/adlnav_v1p3 SCORM-schemas/adlnav_v1p3.xsd

http://www.imsglobal.org/xsd/imsss SCORM-schemas/imsss_v1p0.xsd”>

<metadata>

<schema>ADL SCORM</schema>

<schemaversion>2004 4th Edition</schemaversion>

</metadata>

<organizations default=”ORG-001″>

<organization identifier=”ORG-001″

adlseq:objectivesGlobalToSystem=”false”>

<title>Annual Compliance Training 2026</title>

<imsss:sequencing>

<imsss:controlMode choice=”true” flow=”true”/>

</imsss:sequencing>

<item identifier=”ITEM-001″ identifierref=”RES-SCO-001″>

<title>Module 1: Data Privacy</title>

<adlcp:completionThreshold completedByMeasure=”true” minProgressMeasure=”1.0″/>

<imsss:sequencing>

<imsss:deliveryControls tracked=”true”

completionSetByContent=”true”

objectiveSetByContent=”true”/>

</imsss:sequencing>

</item>

<item identifier=”ITEM-002″ identifierref=”RES-SCO-002″>

<title>Module 2: Code of Conduct</title>

<imsss:sequencing>

<imsss:deliveryControls tracked=”true”

completionSetByContent=”true”

objectiveSetByContent=”true”/>

</imsss:sequencing>

</item>

</organization>

</organizations>

<resources>

<resource identifier=”RES-SCO-001″

type=”webcontent”

adlcp:scormType=”sco”

href=”module-01/index.html”

xml:base=”module-01/”>

<file href=”index.html”/>

<file href=”content.js”/>

</resource>

<resource identifier=”RES-SCO-002″

type=”webcontent”

adlcp:scormType=”sco”

href=”module-02/index.html”>

<file href=”module-02/index.html”/>

</resource>

</resources>

</manifest>

4th Edition-specific notes:

  • adlseq:objectivesGlobalToSystem=”false” should always be explicitly set. The default is true, which means global objectives from this course persist in the LMS and can interfere with other courses for the same learner – a well-documented interoperability hazard.
  • <adlcp:completionThreshold completedByMeasure=”true” minProgressMeasure=”1.0″/> replaces the 3rd Edition child-element pattern. This instructs the LMS to base completion solely on cmi.progress_measure reaching 1.0.
  • xml:base on a resource element sets a path prefix for all <file href> children, reducing redundancy for multi-file SCOs.

SCORM Runtime API: Version Comparison Matrix

The runtime is the JavaScript interface that governs all data exchange between SCO and LMS during a live session. The API object is discovered by the SCO traversing the DOM window hierarchy, SCORM 1.2 looks for an object named API; SCORM 2004 looks for API_1484_11. This naming difference is what causes cross-version failures when a package’s JavaScript library targets the wrong API object.

Capability SCORM 1.2 SCORM 2004 (all editions)
API Object Name API (window/parent) API_1484_11 (window/parent)
Session Start LMSInitialize(“”) Initialize(“”)
Session End LMSFinish(“”) Terminate(“”)
Read Value LMSGetValue(element) GetValue(element)
Write Value LMSSetValue(element, value) SetValue(element, value)
Flush to LMS LMSCommit(“”) Commit(“”)
Error Retrieval LMSGetLastError() GetLastError()
Status Field cmi.core.lesson_status (single field: passed/completed/failed/incomplete/browsed/not attempted) cmi.completion_status + cmi.success_status (split)
Completion Values completed, incomplete, not attempted, browsed (in lesson_status) completed, incomplete, not attempted, unknown (in completion_status)
Success Values passed, failed (in lesson_status) passed, failed, unknown (in success_status)
Score Field cmi.core.score.raw (0–100 decimal) cmi.score.raw + cmi.score.scaled (-1.0 to 1.0)
Suspend Data Limit 4,096 characters (SPM) 64,000 characters (SPM)
Location Bookmark cmi.core.lesson_location (255 chars) cmi.location (1,000 chars)
Session Time cmi.core.session_time (HHHH:MM:SS.SS) cmi.session_time (ISO 8601 duration: PT1H30M)
Learner ID cmi.core.student_id cmi.learner_id
Interactions Write-only Read/write; includes description field
Sequencing Not specified adl.nav.request data model element

The suspend_data size difference is operationally significant: complex Articulate Storyline or Adobe Captivate courses with many variables can overflow the 4,096-character limit on SCORM 1.2, silently truncating bookmarking data and causing learners to lose progress on resume.

LMS and Authoring Tool Compatibility Matrix

LMS / Tool SCORM 1.2 SCORM 2004 3rd Ed SCORM 2004 4th Ed Sequencing Support Max Package Size
Moodle 4.x ✓ Native ✓ Native ✓ Native Partial (known sequencing gaps) Configurable (default 250MB)
Blackboard Ultra ✓ Native ✓ Native ✓ Native Limited 1GB
Canvas (Instructure) ✓ Native ✓ Native Limited Limited 500MB
Docebo ✓ Native ✓ Native ✓ Native ✓ Full 2GB
TalentLMS ✓ Native ✓ Native ✓ Native Partial 2GB
SimpliTrain ✓ Native ✓ Native ✓ Native ✓ Full 2GB
Cornerstone OnDemand ✓ Native ✓ Native ✓ Native ✓ Full 1GB
Absorb LMS ✓ Native ✓ Native ✓ Native Partial 2GB
SCORM Cloud (Rustici) ✓ Reference ✓ Reference ✓ Reference ✓ Full 1GB (free), unlimited (paid)
Articulate Storyline 360 ✓ Export ✓ Export ✓ Export Via imsss N/A
Articulate Rise ✓ Export ✓ Export ✓ Export Single SCO N/A
Adobe Captivate 2024 ✓ Export ✓ Export ✓ Export Limited N/A
iSpring Suite 11 ✓ Export ✓ Export ✓ Export ✓ Via imsss N/A

Sequencing support note: “Partial” means the LMS processes sequencing XML without throwing errors but doesn’t enforce complex rollup or pre/post-condition rules. Test all sequencing logic in SCORM Cloud before assuming LMS behavior matches spec.

Implementation Steps: Authoring and Validating a SCORM 2004 4th Edition Package

These steps cover hand-authored or post-processing workflows. For authoring tool output, start at Step 3.

Step 1: Validate the Manifest XML Before Packaging

Before zipping, run the manifest through an XML validator against the official schemas. A schema-invalid manifest imports successfully in permissive LMSes but fails in strict ones. Use the ADL SCORM 2004 4th Edition Test Suite (available at adlnet.gov) for conformance-level validation, or SCORM Cloud for rapid functional testing.

Step 2: Verify the adlcp:scormType Attribute on Every Resource

Every <resource> element that launches content to the learner must declare adlcp:scormType=”sco”. Resources without this attribute, or with adlcp:scormType=”asset”, will not trigger runtime API communication – the LMS will not attempt to track them.

Step 3: Confirm the ZIP Root Structure

The ZIP must be created by selecting all files inside the course folder and compressing them – not by right-clicking the containing folder. The correct result: opening the ZIP shows imsmanifest.xml and the schema folder immediately, not a subfolder with those items inside.

On macOS: use cd to the course directory, then zip -r ../course-name.zip . -x “*.DS_Store” -x “__MACOSX/*”. The default macOS Finder “Compress” adds a __MACOSX/ metadata folder that some LMSes misparse.

Step 4: Test in SCORM Cloud Before LMS Upload

SCORM Cloud (cloud.scorm.com) is the de facto conformance reference. If a package fails in SCORM Cloud, the issue is in the package. If it passes SCORM Cloud but fails in your LMS, the issue is LMS-specific. This isolation test saves hours of debugging.

Step 5: Check the schemaversion Value Against Your LMS’s Parser

For SCORM 2004, the valid schemaversion values are: CAM 1.3 (2nd Edition), 2004 3rd Edition, 2004 4th Edition. Using the wrong edition string can cause the LMS to misidentify the package version and apply incorrect sequencing rules or reject the import entirely. Many authoring tools default to 2004 3rd Edition even when generating 4th Edition features – verify the output manifest.

Step 6: Audit the <file> Elements in <resources>

Every file the SCO loads at runtime should be listed in the manifest’s <file> elements. The spec doesn’t require complete enumeration for runtime function (the content runs from the filesystem regardless), but LMSes that pre-stage or cache content at import time use the <file> list as the copy manifest. Missing entries cause 404 errors in hosted and cloud LMS environments.

Common Issues and Fixes

Error 1: “Manifest Not Found” on Import

Symptom: LMS rejects the ZIP with “manifest not found,” “missing imsmanifest.xml,” or “could not parse SCORM package.”

Root cause (most common): The ZIP was created by compressing the parent folder, placing imsmanifest.xml at course-folder/imsmanifest.xml inside the ZIP instead of at the root. On macOS, Finder’s “Compress” creates exactly this structure.

Fix: Unzip, navigate inside the course folder, select all contents, and re-zip. Confirm by opening the resulting ZIP – imsmanifest.xml must be visible at the first level with no containing folder. For macOS exports from Articulate Rise or Storyline, always re-export directly from the tool; don’t compress the downloaded folder.

Error 2: API Not Found / LMSInitialize Returns false

Symptom: The SCO launches but never reports tracking data. Browser console shows Cannot read properties of undefined (reading ‘LMSInitialize’) or the equivalent.

Root cause: The SCO’s API discovery routine can’t find the API (1.2) or API_1484_11 (2004) object. This happens when the LMS launches content in a new popup window without attaching the API to window.opener, or when a cross-origin iframe restricts DOM traversal.

Fix: Check the LMS’s launch mode setting – frameset mode reliably exposes the API to iframe content; new window mode requires the SCO to search window.opener. If the content is served from a different domain than the LMS API (split CDN hosting), the browser’s cross-origin policy blocks parent-frame access. Either serve all content from the same origin or configure the LMS’s Content-Security-Policy to permit the content domain.

Error 3: Course Shows “Completed” Immediately on Launch

Symptom: The LMS marks the course complete as soon as it opens, before the learner does anything.

Root cause: The <adlcp:masteryscore> element is absent or set to 0 in the manifest, and the SCO calls LMSSetValue(“cmi.core.lesson_status”, “completed”) during initialization rather than at actual completion. This is a common authoring tool misconfiguration.

Fix: Open imsmanifest.xml and verify <adlcp:masteryscore> contains a non-zero threshold (e.g., 80). Then inspect the SCO’s JavaScript for early lesson_status sets. Authoring tools like Articulate Storyline have a “Complete when viewed” option that triggers completion on slide 1 – switch to “Complete course when learner passes quiz” for assessment-gated content. In Moodle, the admin setting “Mastery score overrides status” controls whether masteryscore in the manifest takes precedence over the SCO’s own status calls.

Error 4: Learner Progress Lost on Resume (Bookmark Failure)

Symptom: A learner exits mid-course and resumes from the beginning instead of the last visited slide.

Root cause: The SCO is writing cmi.core.suspend_data (or cmi.suspend_data in 2004) but either: (a) the data exceeds the 4,096-character SCORM 1.2 limit and is being truncated, (b) the SCO sets cmi.core.exit to “” (empty) instead of suspend on unload, causing the LMS to treat the session as terminated rather than suspended, or (c) the SCO reads cmi.core.entry but doesn’t check for ab-initio (fresh start) vs resume.

Fix: Verify cmi.core.exit is set to suspend before LMSFinish() on unload. For SCORM 1.2 courses with large state (Storyline with many branching variables), publish to SCORM 2004 to access the 64,000-character suspend_data limit. Confirm the LMS’s “New attempt on re-launch” setting isn’t forcing ab-initio on every entry.

Error 5: Sequencing Rules Ignored / Learner Can Access SCOs Out of Order

Symptom: SCORM 2004 package with forced-sequential imsss:sequencing allows learners to jump to any module.

Root cause: The LMS doesn’t implement IMS Simple Sequencing beyond basic parsing. Many LMSes (including Moodle and Canvas) accept sequencing XML without error but don’t enforce controlMode, preConditionRule, or rollup logic. This is a known compliance gap documented in the ADL’s conformance testing reports.

Fix: Test sequencing in SCORM Cloud to confirm the rules work as intended in a reference player. For LMSes with partial sequencing support, implement navigation locking at the SCO level (JavaScript-driven prerequisite checks inside each module) as a fallback. Accept that true IMS Simple Sequencing enforcement requires an LMS that has passed ADL’s sequencing conformance tests.

Error 6: Score Not Passing to LMS Gradebook

Symptom: The SCO completes and shows a score internally, but the LMS gradebook shows null, 0, or no entry.

Root cause: For SCORM 1.2, the SCO writes to cmi.core.score.raw but the LMS reads from cmi.core.lesson_status to determine pass/fail. If lesson_status is set to completed without evaluating the mastery score, the LMS records completion with no grade. For SCORM 2004, cmi.score.raw and cmi.score.scaled are separate – some LMSes display raw (0–100) and others display scaled (-1.0 to 1.0). If only one is set, the other column appears blank.

Fix: In SCORM 1.2, set cmi.core.lesson_status to passed or failed (not just completed) based on score comparison against mastery threshold. For SCORM 2004, set both cmi.score.raw and cmi.score.scaled (scaled = raw / max). Confirm which score field your LMS gradebook is configured to display – this is an admin-configurable setting in most enterprise LMSes.

💡 Admin Insight: The masteryscore Trap in Multi-SCO Courses

When a SCORM 1.2 package contains multiple SCOs, the <adlcp:masteryscore> element must be declared on each <item> individually – it is not inherited from the parent organization. A common authoring tool oversight sets the mastery score only at the organization level or omits it entirely from child items. The result: the first SCO respects the threshold, subsequent SCOs mark “passed” the moment they launch. Additionally, some LMSes (notably older Cornerstone and SumTotal versions) override cmi.core.lesson_status with their own completion logic derived from masteryscore regardless of what the SCO sets – which can cause a course to show “passed” even when the SCO explicitly reports “failed.” Always test each SCO in isolation on a target LMS using SCORM debugger tools like pipwerks/SCORM-API-wrapper or the browser console with window.API before a full course upload

FAQ

Q1. What's the practical difference between declaring a resource as sco vs asset in adlcp:scormType, and does it matter if I get it wrong?

Yes, it matters significantly. A resource declared as sco signals to the LMS that the content will initiate API communication – the LMS creates a tracking record for the learner against that SCO, waits for LMSInitialize/Initialize, and persists whatever data the SCO writes. A resource declared as asset (or with scormType omitted) tells the LMS the content is static – no tracking record is created, no API calls are expected, and the LMS marks it “satisfied” or “completed” immediately on launch (behavior varies by LMS). If a module that does send API calls is declared as asset, many LMSes will accept the calls but not persist the data, or will throw a runtime error because the API wasn’t attached.

Q2. SCORM Cloud passes my package but our Moodle instance fails to track completion. How do I isolate the problem?

Start with the browser’s JavaScript console open during a test launch in Moodle. Look specifically for: API initialization errors (returned false from LMSInitialize), 403/404 responses from the Moodle SCORM endpoint, or cross-origin policy errors. Then compare Moodle’s SCORM debug report (accessible via the course’s SCORM activity → Reports → tracked data) against what SCORM Cloud shows for the same interaction. If the API calls reach Moodle but the status isn’t written, check Moodle’s SCORM activity settings – specifically “Attempt management” (whether a new attempt is forced on each launch) and “Display package” (iframe vs new window), both of which can silently break tracking. Also verify Moodle’s maxbytes and scorm_maxattempts admin settings aren’t interfering.

Q3. Should new projects use SCORM 2004 4th Edition or SCORM 1.2 in 2026?

For most enterprise deployments: SCORM 1.2 remains the safer default unless you specifically need SCORM 2004 features. SCORM 1.2 has near-universal LMS support with consistent behavior; SCORM 2004’s sequencing features are not reliably implemented across major platforms. Choose SCORM 2004 4th Edition when you need: the 64,000-character suspend_data limit (Storyline-heavy courses with many variables), the split completion_status/success_status model for cleaner audit reporting, cmi.progress_measure for percentage-based completion, or mandatory complex adaptive branching. For new projects where offline delivery, mobile, or cross-platform analytics matter, evaluate cmi5 (the ADL-maintained xAPI profile specification, published 2016) as the forward-looking alternative – it resolves most SCORM structural constraints while maintaining LMS compatibility through a defined launch mechanism.

James Smith

Written by James Smith

James is a veteran technical contributor at LMSpedia with a focus on LMS infrastructure and interoperability. He Specializes in breaking down the mechanics of SCORM, xAPI, and LTI. With a background in systems administration, James