If your SCORM content silently fails to record completions when learners close a browser tab, your popup-based SCORM player is blocked by corporate browsers, or you’re trying to deliver courses from a CDN without same-domain restrictions – you already have operational reasons to evaluate cmi5. The cmi5 specification (current version: Quartz, maintained at github.com/AICC/CMI-5_Spec_Current since ADL assumed stewardship in 2014) eliminates every one of those failure modes by replacing SCORM’s JavaScript DOM traversal model with RESTful HTTP communication via xAPI 1.0.3. This guide covers the architecture, implementation flow, LMS compatibility, and the specific mistakes documented in ADL’s own conformance requirements that appear in production deployments.
The cmi5 Architecture: What Actually Changed from SCORM
The Fundamental Model Shift
SCORM communicates via a JavaScript API object injected into the browser’s window tree by the LMS. The SCO finds it by recursively walking window.parent until it hits API (SCORM 1.2) or API_1484_11 (SCORM 2004). This model requires:
- A shared browser context between content and LMS
- Content hosted on the same domain (or a domain that survives the browser’s cross-origin policy)
- A browser to exist at all
cmi5 replaces this entirely. Communication flows over HTTP to a Learning Record Store (LRS) using xAPI 1.0.3 statements. The AU (Assignable Unit – cmi5’s equivalent of a SCO) discovers its LRS endpoint and authorization token via URL query string parameters passed at launch. No DOM traversal. No shared browser context. No domain restriction.
The Three Core Components
Assignable Unit (AU): The launchable content unit. Unlike a SCORM SCO, the AU’s actual files do not need to reside in or be imported into the LMS. The AU can live on a CDN, a separate server, or inside a native mobile app. Only its URL and metadata are referenced in the course structure.
Learning Record Store (LRS): The xAPI-compliant web service that receives, stores, and retrieves statements. Under cmi5, the LMS must either implement an LRS internally or integrate with an external one. The AU communicates directly with the LRS (not the LMS) for all statement submission – a critical distinction.
cmi5.xml Course Structure File: The direct replacement for SCORM’s imsmanifest.xml. Defines courses, blocks, and AUs in a hierarchical structure with completion criteria (moveOn), mastery scores, and launch parameters. The file must be named cmi5.xml when packaged in a ZIP. AU file resources may or may not be in that ZIP.
The Launch URL Parameters (All Six, Specified in Section 8.1)
When the LMS launches an AU, it appends these query string parameters to the AU’s URL:
endpoint → Base URL of the LRS (for all xAPI calls)
fetch → One-time-use URL the AU POSTs to for an auth token
registration → UUID identifying this learner’s enrollment instance
activityId → LMS-generated UUID for this AU (MUST differ from publisher ID)
actor → JSON-encoded xAPI Agent (learner identity)
returnURL → (Optional) URL the AU redirects to on exit
A fully formed launch URL looks like this:
https://content.company.com/modules/safety-101/index.html
?endpoint=https://lrs.company.com/xapi/
&fetch=https://lms.company.com/cmi5/fetch/a1b2c3d4
®istration=e5f6a7b8-c9d0-4e1f-8g2h-i3j4k5l6m7n8
&activityId=https://lms.company.com/activities/safety101-001
&actor=%7B%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B…%7D%7D
&returnURL=https://lms.company.com/learner/dashboard
The fetch URL is single-use by specification. The AU POSTs to it with no body and receives a JSON response:
{ “auth-token”: “Basic dXNlcjpwYXNzd29yZA==” }
This token is then used as the Authorization header for all subsequent xAPI HTTP requests to the LRS endpoint. The one-time nature of the fetch URL is a deliberate security design: it prevents token replay and forces each launch session to generate a fresh credential. Any implementation that calls the fetch URL more than once – a common authoring tool bug on page refresh – will receive an error response on the second call.
The Nine cmi5 Defined Verbs (Section 9.3)
cmi5 defines a controlled vocabulary of verbs for “cmi5 defined” statements. Only these verbs carry the cmi5 category context activity (https://w3id.org/xapi/cmi5/context/categories/cmi5), which is how the LMS identifies and evaluates them for moveOn logic:
| Verb | Issuer | Once Per Session? | Notes |
|---|---|---|---|
| launched | LMS | Yes | Sent before AU launch; includes sessionId |
| initialized | AU | Yes | First statement AU sends; signals readiness |
| completed | AU | Yes | Learner has experienced all content |
| passed | AU | Yes | Score ≥ masteryScore; MUST include scaled score if masteryScore exists |
| failed | AU | Yes | Score < masteryScore |
| abandoned | LMS | Yes | LMS detects abnormal session end |
| waived | LMS | Yes | LMS grants credit without learner launching |
| terminated | AU | Yes | Final statement AU sends; signals end of session |
| satisfied | LMS | Yes per block/course | Issued by LMS when moveOn criteria are met |
AUs may also send “cmi5 allowed” statements – any xAPI statement with any verb – between initialized and terminated, as long as they include the session ID and registration in context. These custom statements (e.g., interaction-level data, video progress via the xAPI Video Profile) are stored by the LRS but are not evaluated by the cmi5 completion engine.
The moveOn Criteria Options (Section 13.1.4)
moveOn is set per AU in the course structure and determines what the LMS requires before marking that AU as “satisfied”:
| moveOn Value | Requirement |
|---|---|
| Passed | AU must send a passed statement |
| Completed | AU must send a completed statement |
| CompletedAndPassed | AU must send both |
| CompletedOrPassed | AU must send either |
| NotApplicable | AU is immediately satisfied on registration – no launch required |
Critical ADL-documented mistake: If a course structure omits moveOn for all AUs (defaulting them all to NotApplicable), the entire course is marked satisfied the moment the learner registers – before they launch a single AU. This is conformant behavior but almost certainly not the course designer’s intent. Validate moveOn in every AU during content review.
The State API Document: What the LMS Writes Before Launch
Before launching any AU, the LMS must write a State API document to the LRS at the activity state endpoint. This document (the LMS.LaunchData state) contains the context template the AU must use in all cmi5 defined statements:
{
“contextTemplate”: {
“extensions”: {
“https://w3id.org/xapi/cmi5/context/extensions/sessionid“: “e5c1de64-90c8-4549-a08f-074696876809”
},
“contextActivities”: {
“grouping”: [
{ “id”: “https://w3id.org/xapi/cmi5/context/categories/cmi5” }
]
}
},
“launchMode”: “Normal”,
“launchParameters”: “”,
“masteryScore”: 0.8,
“moveOn”: “CompletedAndPassed”,
“returnURL”: “https://lms.company.com/learner/dashboard”,
“entitlementKey”: { “courseStructure”: “https://lms.company.com/courses/safety-101” }
}
The AU reads this document after retrieving its auth token and must use the contextTemplate from it – not a hardcoded context – in all cmi5 defined statements. The LMS may have administratively overridden values like masteryScore from what was in the original course structure. Ignoring the State API document and using hardcoded values is one of the most frequently documented conformance violations.
The cmi5.xml Course Structure
A multi-AU course structure with blocks:
<?xml version=”1.0″ encoding=”utf-8″?>
<courseStructure xmlns=”https://w3id.org/xapi/profiles/cmi5/v1/CourseStructure.xsd”>
<course id=”https://courses.company.com/safety-2026″>
<title><langstring lang=”en-US”>Safety Compliance 2026</langstring></title>
<description><langstring lang=”en-US”>Annual safety training</langstring></description>
<block id=”https://courses.company.com/safety-2026/module1″>
<title><langstring lang=”en-US”>Module 1: Hazard Recognition</langstring></title>
<au id=”https://courses.company.com/safety-2026/module1/content”
moveOn=”Completed”
masteryScore=”0.8″
launchMethod=”OwnWindow”>
<title><langstring lang=”en-US”>Hazard Recognition Content</langstring></title>
<url>https://content.cdn.com/safety-2026/module1/index.html</url>
</au>
<au id=”https://courses.company.com/safety-2026/module1/assessment”
moveOn=”Passed”
masteryScore=”0.8″
launchMethod=”OwnWindow”>
<title><langstring lang=”en-US”>Module 1 Assessment</langstring></title>
<url>https://content.cdn.com/safety-2026/module1/quiz/index.html</url>
</au>
</block>
</course>
</courseStructure>
Note that the AU url values are fully qualified – they can point to any server. The actual content files are not imported into the LMS. Only this XML is.
cmi5 LMS, Authoring Tool & LRS Compatibility Matrix [2026]
LMS Platform Support
| LMS | cmi5 Support | Implementation Notes |
|---|---|---|
| Rustici SCORM Engine / SCORM Cloud | ✅ Full | Reference implementation; use for conformance testing |
| Moodle 4.x | ✅ Via plugin | Requires H5P/xAPI plugin or Moodle SCORM cmi5 module; native cmi5 module in roadmap |
| TalentLMS | ✅ Native | Upload ZIP via SCORM/xAPI/cmi5 activity type; integrated LRS |
| Docebo | ✅ Native | Supports cmi5 alongside xAPI; requires internal LRS configuration |
| Cornerstone OnDemand | ⚠️ Partial | Some clients report using Rustici Engine backend; verify moveOn and block support |
| SAP SuccessFactors Learning | ⚠️ Partial | cmi5 support available but maturity varies by version; test against SAP SF Mobile separately |
| Absorb LMS | ✅ Native | Full cmi5 support with built-in LRS |
| Canvas (Instructure) | ⚠️ Via LTI/xAPI | No native cmi5 launch; third-party LRS integration required |
| Blackboard Learn | ⚠️ Via integration | External LRS required; not plug-and-play |
| 360Learning | ❌ Not supported | SCORM only as of early 2025 |
Vendor verification note: LMS vendors frequently claim “cmi5 support” when they mean “we can import the cmi5.xml and launch the content.” Actual conformance requires: correct fetch URL token issuance, State API document creation before each launch, moveOn evaluation including block rollup, satisfied statement issuance, and launchMode (Normal/Browse/Review) handling. Ask specifically whether each of these is implemented before assuming full conformance.
Authoring Tool Export Support
| Tool | cmi5 Export | Version |
|---|---|---|
| Articulate Storyline 360 | ✅ | Since 2021 updates; exports cmi5.xml + AU files in ZIP |
| Articulate Rise 360 | ✅ | Full cmi5 export |
| Adobe Captivate | ✅ | Since Captivate 2019 update |
| Lectora Online / Desktop | ✅ | Full cmi5 export with moveOn options |
| iSpring Suite | ✅ | Native cmi5 export since Suite 11 |
| dominKnow CLARO | ✅ | Full cmi5 with xAPI extensions |
| Evolve | ✅ | cmi5 export supported |
| Camtasia | ❌ | No cmi5; SCORM 1.2 only |
Standalone LRS Options (Required for External LRS Architecture)
| LRS | Standards | Notes |
|---|---|---|
| SCORM Cloud LRS | xAPI 1.0.3, cmi5 | Rustici’s hosted LRS; easiest integration |
| Watershed LRS | xAPI 1.0.3, cmi5 | Strong analytics; common enterprise choice |
| Learning Locker (HT2) | xAPI 1.0.3, cmi5 | Open source; requires setup expertise |
| GrassBlade LRS | xAPI 1.0.3 | WordPress-native; cmi5 via SCORM Cloud integration |
| TRAX LRS | xAPI 1.0.3 | Open source, Laravel-based |
Implementation Steps for LMS Admins and Developers
Phase 1: Verify LMS cmi5 Conformance Before Content Development
Before investing in authoring tool exports, confirm your LMS handles the full cmi5 session lifecycle. The ADL’s CATAPULT project (github.com/adlnet/CATAPULT) provides a conformance test suite and reference AU player. Run CATAPULT’s test suite against your LMS’s cmi5 implementation to verify:
- Fetch URL issues a valid auth-token and returns an error on second call
- State API document is written before each AU launch with correct contextTemplate, moveOn, masteryScore, launchMode, and returnURL
- satisfied statements are issued for blocks and the course when moveOn criteria are met
- abandoned statements are issued when the LMS detects a session terminated without a terminated statement from the AU
If your LMS uses Rustici Engine as its backend (many commercial LMS platforms do), it has passed this conformance. If it’s a custom implementation, run CATAPULT.
Phase 2: Authoring Tool Configuration (Articulate Storyline 360)
- Publish > LMS > Select cmi5
- Under Reporting, set moveOn to match your LMS admin expectations:
- Passed/Incomplete → use Passed or CompletedAndPassed in cmi5
- Complete/Incomplete → use Completed
- In the Player settings, uncheck “Launch player in new window” if your LMS uses launchMethod=”AnyWindow” in its generated course structure. For OwnWindow, the LMS handles the window context.
- Under Output Options, set a unique, stable AU identifier – this becomes the publisher ID in cmi5.xml. It must be an IRI (e.g., https://yourcompany.com/courses/module1/au1). Do not use auto-generated GUIDs that change on republish; this will break registration continuity.
Phase 3: Course Structure Import and Registration Setup
- Import the cmi5.xml (or ZIP containing it) into your LMS.
- Verify the LMS has parsed all AUs and blocks correctly and has not flattened the block hierarchy. Block rollup (a block being satisfied when all its children are satisfied) is required by the spec but inconsistently implemented.
- Before assigning to learners: confirm moveOn values. If the LMS allows you to override them at the admin level, ensure you’re reading from the State API document in your AU, not from the course structure directly.
- Create a test enrollment. Using your LMS’s admin view or a direct LRS query, verify the launched statement is sent with the moveOn and sessionId values before the AU initializes.
Phase 4: LRS Configuration for Reporting
cmi5’s reporting advantage over SCORM only materializes if your LRS is queried correctly. The cmi5 category context activity IRI https://w3id.org/xapi/cmi5/context/categories/cmi5 is the standard filter to isolate cmi5 defined statements from the full xAPI statement stream. In your LRS reporting queries:
GET /xapi/statements
Authorization: Basic <admin-token>
X-Experience-API-Version: 1.0.3
Content-Type: application/json
?activity=https://w3id.org/xapi/cmi5/context/categories/cmi5
&related_activities=true
®istration=<registration-uuid>
This returns all cmi5 defined statements for a specific registration. To filter further for completion analysis, add ?verb=http://adlnet.gov/expapi/verbs/completed.
Phase 5: Launch Mode Handling (Normal, Browse, Review)
The State API document’s launchMode field controls what statements the AU is allowed to send:
- Normal: Full session – AU may send all cmi5 defined statements.
- Browse: The AU MUST send only initialized and terminated. No completed, passed, or failed. Used for preview without affecting completion status.
- Review: Same restrictions as Browse. Used for reviewing already-completed content.
AUs that ignore launchMode and send completed or passed statements during Browse or Review sessions are non-conformant (ADL mistakes document, item 3). LMS admins seeing unexpected completions on review attempts should check whether their AU is reading and respecting launchMode.
Common cmi5 Implementation Errors and Fixes
Error 1: Fetch URL Called More Than Once – Session Fails on Page Refresh
Symptom: AU loads normally, learner refreshes the browser mid-course, AU fails to reinitialize. LRS may log a 4xx error. No completion recorded.
Root cause: On page refresh, the AU calls the fetch URL again for a new auth token. Per Section 8.2.3 of the cmi5 spec, the fetch URL is one-time use. The second call returns an error response, not a token. If the AU doesn’t handle this gracefully, the entire session fails.
Fix (AU developer): On first token retrieval, store the token in non-volatile session storage (not sessionStorage, which is tab-scoped and survives refresh but not tab close). On page load, check for an existing token before calling the fetch URL. Per ADL best practices: “AUs should be designed to use non-volatile storage local to the AU to preserve the state of operations that must occur only once in a session.” In practice, use localStorage with the sessionId as the key.
Fix (LMS admin): If your AU is from an authoring tool, report this to the vendor. Most modern authoring tools (Storyline 360, Rise, Lectora post-2022) handle this correctly. Older exports may not.
Error 2: Course Satisfied Immediately on Registration – Before Any Launch
Symptom: Learners appear to have completed the course the moment they’re enrolled. No statements beyond the satisfied statement appear in the LRS for those learners.
Root cause: All AUs in the course structure have moveOn=”NotApplicable” – either explicitly set or defaulted to it because the authoring tool omitted moveOn entirely from the XML. The cmi5 spec requires the LMS to evaluate moveOn at registration time and issue satisfied for any AU with NotApplicable. If all AUs are NotApplicable, the course is immediately satisfied.
Fix: Open cmi5.xml from your authoring tool output and verify every <au> element has a moveOn attribute other than NotApplicable. In Storyline 360: verify you’re publishing with a completion tracking setting selected. The moveOn attribute in the exported cmi5.xml should be Passed, Completed, CompletedAndPassed, or CompletedOrPassed.
Error 3: AU Uses Publisher ID as Object ID Instead of LMS-Generated activityId
Symptom: LMS reporting shows no completions even though the LRS contains completed statements. Statements are in the LRS but not linked to the correct registration.
Root cause: The cmi5 spec requires the LMS to generate a unique activityId for the AU (separate from the publisher’s ID in the course structure) and pass it as a query string parameter. All cmi5 defined statements from the AU must use this LMS-generated activityId as the object ID, not the publisher ID from the course structure. AUs that use their own hardcoded ID or the publisher ID will send statements the LMS cannot match to the correct course enrollment.
Fix (AU developer): Read activityId from the launch URL query string. Per Section 8.1 of the spec: “The AU MUST get the activityId value from the query string. The AU MUST use the activityId value as the ID property of the Object in all cmi5 defined statements.” Additionally, include the publisher ID in the context activities grouping array per Section 9.6.2.3.
Error 4: Passed/Failed Statements Sent Without Checking masteryScore from State API
Symptom: Learners who scored below the required threshold appear as “passed” in the LMS. Or, learners who met the score appear as “failed.”
Root cause: The AU is using a hardcoded score threshold internally rather than reading masteryScore from the State API document. The LMS administrator may have set a different masteryScore than what the course designer specified in cmi5.xml. Per Section 9.3.6: “If the passed statement contains a scaled score, the scaled value MUST be equal to or greater than the masteryScore indicated in the LMS Launch Data.”
Fix: The AU must read masteryScore from the State API document and use it as the threshold for passed/failed determination – not a value compiled into the content. Report to your authoring tool vendor if this behavior is in a tool export. For custom AU development, always fetch and parse the LMS.LaunchData state document before any scoring logic runs.
Error 5: returnURL Missing or AU Doesn’t Redirect on Exit – Learner Stranded
Symptom: Learner completes course, clicks “Exit,” and lands on a blank page or a “window closed” message. They must manually navigate back to the LMS.
Root cause: Either the LMS is not providing returnURL in the State API document, or the AU is not redirecting to it after sending the terminated statement. The returnURL is technically optional in the spec, but ADL best practices note it as expected for browser-based launches: “The consequence of this mistake is rather significant, as the learner cannot return to the LMS user interface after exit.”
Fix (LMS admin): Confirm your LMS is populating returnURL in the State API document. Check this via a direct LRS query of the LMS.LaunchData state document for a test session. If your LMS is not writing returnURL, report to the vendor.
Fix (AU developer): After sending the terminated statement, check for returnURL in the launch data and redirect: window.location.href = launchData.returnURL. Do not use window.close() as a fallback – this does not work in most browser configurations for non-popup windows.
Error 6: Block Rollup Not Triggering Satisfied – Multi-AU Course Never Completes
Symptom: In a course with multiple AUs organized into blocks, individual AUs show as completed in the LRS, but the course-level satisfied statement is never issued. The LMS shows the course as perpetually “in progress.”
Root cause: The LMS is not correctly implementing block rollup – the process of evaluating whether all AUs within a block have met their moveOn criteria, and then issuing a satisfied statement for the block, which in turn propagates to the course level. This is a known partial-implementation issue in some LMS platforms.
Fix: Run the CATAPULT conformance test for the “Block Rollup Scenario (PassedAndCompleted moveOn)” – this is a specific test case in the conformance suite that isolates this behavior. If the LMS fails this test, escalate to the vendor. As a workaround for existing deployments, restructure your course as a flat list of AUs at the root level (no nested blocks) until the LMS vendor resolves rollup support.
💡 LMS Admin Pro Tip:
When evaluating whether your LMS “supports cmi5,” run a test enrollment with a multi-block course structure from the ADL’s CATAPULT example templates – specifically the Pre/Post Test framed example. This exercises all the behaviors that partial implementations miss: block rollup, multi-AU moveOn evaluation, Browse mode restrictions, and the satisfied statement chain from AU → Block → Course. A vendor’s “yes, we support cmi5” response is meaningless without a multi-block rollup test passing. The CATAPULT test AU (github.com/adlnet/CATAPULT) provides simulated AU behavior that covers every statement ordering requirement in the spec – it’s the only reliable way to validate an LMS implementation without building your own test content.
FAQ
Q1. Our LMS vendor says they "support xAPI." Does that mean cmi5 will work?
No. xAPI and cmi5 are not the same thing. xAPI (1.0.3) is the data format and transport protocol – it defines statements, actors, verbs, objects, and the LRS HTTP API. cmi5 is a profile that adds rules on top of xAPI specifically for LMS-launched content: how the LMS generates a fetch URL, how it writes the State API document, how it evaluates moveOn, how it handles block rollup, how it issues satisfied statements. An LMS that “supports xAPI” can receive and store xAPI statements. It may not implement any of the launch, token, State API, or moveOn evaluation requirements that cmi5 requires. These are entirely separate capabilities. Always ask specifically: “Does your LMS implement the cmi5 launch protocol, State API, fetch URL, and moveOn evaluation?” Those are the four minimum requirements for real cmi5 support.
Q2. Can we run cmi5 and SCORM content side-by-side in the same LMS during a migration period?
Yes – and this is the recommended migration approach. All cmi5-capable LMS platforms that support SCORM also continue to serve SCORM packages normally, since the content types use entirely different communication paths. There is no conflict between having SCORM 1.2 courses and cmi5 courses in the same catalog. The practical transition strategy is: keep existing SCORM content as-is if it’s stable and meet tracking requirements, and publish new strategic content as cmi5. A useful checkpoint for migrating an existing course: if the SCORM version is generating support tickets around completions not recording in Safari or mobile, and the course is due for a content revision anyway, the revision cycle is the natural point to republish as cmi5. The content rebuild overhead is equivalent; the runtime reliability is significantly better.
Q3. The cmi5 spec references an IEEE review. Does that affect current implementations?
The cmi5 specification has been submitted for IEEE standardization (visible in the GitHub issues labeled IEEE_pre_review_1). Several open issues have been deferred to a future major version specifically to avoid disrupting the IEEE review process. Current implementations should target the Quartz version of the spec at github.com/AICC/CMI-5_Spec_Current. The Quartz version is the stable, implementable release. Quartz superseded the developer-preview Sandstone version, and items tagged “Defer Until Next Major Release” in the GitHub issues will not affect Quartz conformance. The IEEE process, if it results in a finalized standard, will align the specification with IEEE’s requirements for a formal international standard – it will not retroactively break Quartz-conformant implementations.
SCORM to cmi5 Terminology Mapping
| SCORM Term | cmi5 Equivalent | Key Difference |
|---|---|---|
| SCO (Shareable Content Object) | AU (Assignable Unit) | AU URL can be any location; SCO must be in the same package |
| imsmanifest.xml | cmi5.xml | cmi5.xml references external AU URLs; manifest bundles all resources |
| JavaScript API object | xAPI LRS endpoint | HTTP REST vs. DOM traversal |
| LMSInitialize() | initialized statement | Statement to LRS vs. function call in browser |
| LMSFinish() | terminated statement | Statement to LRS vs. function call in browser |
| cmi.core.lesson_status | completed / passed / failed verbs | Explicit statements vs. a single status field |
| cmi.suspend_data (4,096 chars) | xAPI State API document (unlimited) | JSON document, any size |
| Sequencing rules (SCORM 2004) | moveOn + block hierarchy | Simpler model; no IMS Simple Sequencing complexity |
| SCORM package (ZIP with all resources) | cmi5 package (cmi5.xml + optional resources) | Content can remain on remote servers |