cmi5 in one paragraph
What is cmi5? It is a package specification, published by ADL in 2016, that tells an LMS how to import, launch, and roll up content that reports through xAPI. The package is a zip with a manifest called cmi5.xml at its root, listing one or more launchable units and, for each, the rule that says what "done" means. When a learner launches a unit, the LMS gives it the address of a learning record store, a one-time URL to fetch a session token, the learner's identity, and a registration id; the unit posts a defined sequence of xAPI statements to the store, and the LMS reads those same statements to decide whether the unit is satisfied. If xAPI is new to you, read What is xAPI first — cmi5 assumes it.
The cmi5 package and its manifest
Unzip a cmi5 package and you find cmi5.xml at the root, plus whatever HTML, script, and media the content needs — or nothing else at all, because cmi5 allows a unit's URL to be absolute, pointing at content hosted elsewhere. A manifest-only package that launches content from your own server is legal and common. (SCORM's specification has no equivalent; the nearest thing is the launcher-package pattern in SCORM dispatch explained.)
url may be relative to the zip or absolute.The manifest is small. This one is complete and would import into a conformant LMS:
<?xml version="1.0" encoding="UTF-8"?>
<courseStructure xmlns="https://w3id.org/xapi/profiles/cmi5/v1/CourseStructure.xsd">
<course id="https://example.org/courses/fire-safety">
<title><langstring lang="en-US">Fire Safety</langstring></title>
<description><langstring lang="en-US">Annual fire safety refresher.</langstring></description>
</course>
<au id="https://example.org/courses/fire-safety/module-1"
moveOn="CompletedAndPassed" masteryScore="0.8" launchMethod="AnyWindow">
<title><langstring lang="en-US">Module 1: Evacuation</langstring></title>
<description><langstring lang="en-US">Routes, assembly points, wardens.</langstring></description>
<url>module-1/index.html</url>
</au>
</courseStructure>
Compare that with an imsmanifest.xml: no <resources> listing every file, no <organizations> tree separate from the items, no schema-version metadata block. The course and each au carry an id that is an IRI — a URL-shaped identifier — and those ids become the object.id of every statement the content sends. Change an id between versions and the LMS treats it as a different course, so pick them once. Grouping uses <block> elements, which nest aus and other blocks; the XSD lives at the namespace URL, and validating against it before upload catches most import failures.
Assignable units
An assignable unit, or AU, is cmi5's launchable thing — the counterpart of a SCORM SCO. Each <au> has a url and three attributes that decide how the LMS treats it.
| Attribute | Values | What it controls |
|---|---|---|
moveOn | Passed, Completed, CompletedAndPassed, CompletedOrPassed, NotApplicable | Which statement(s) from the AU make the LMS mark it satisfied. NotApplicable means it is satisfied on launch. |
masteryScore | Decimal 0–1, optional | The LMS passes it to the AU at launch. If a passed statement carries result.score.scaled, that value must be ≥ masteryScore; if a failed statement carries one, it must be below it. |
launchMethod | AnyWindow, OwnWindow | Whether the LMS may launch the AU in an iframe or must open a new window. |
This is the biggest practical difference from SCORM: the completion rule is declared in the manifest and evaluated by the LMS, not decided silently inside the content. A SCORM 1.2 SCO decides for itself when to write cmi.core.lesson_status = "completed"; a cmi5 AU sends completed and passed statements and moveOn says which combination counts. Two AUs with identical content and different moveOn values produce different course results.
The launch handshake
SCORM content finds a JavaScript object (API or API_1484_11) in a parent window. cmi5 content gets everything from its own launch URL and two HTTP calls, in a sequence the specification fixes:
Step by step, from the AU's side:
- Parse the launch URL. Five query parameters arrive:
endpoint(the LRS base URL),fetch(a URL),actor(a JSON Agent, always with anaccountidentifier under cmi5),registration(a UUID), andactivityId(the AU's id from the manifest). - POST to the fetch URL with an empty body. The response is
{"auth-token": "…"}; use it asAuthorization: Basic <token>on every LRS request this session. The fetch URL is one-time use — a second POST returns{"error-code": "1", "error-text": "…"}— which is what stops a credential in browser history from being replayed, and is the piece query-string xAPI launch lacks. - GET the launch data.
GET <endpoint>/activities/state?stateId=LMS.LaunchData&activityId=…&agent=…®istration=…returns JSON withlaunchMode(Normal,Browse, orReview),moveOn,masteryScore, an optionalreturnURL, any manifestlaunchParameters, and acontextTemplate. - Send
initializedfirst, and once. Every cmi5-defined statement is built from thecontextTemplate: it fixescontext.registration, asessionidextension, and the category activityhttps://w3id.org/xapi/cmi5/context/categories/cmi5that marks a statement as one the LMS should interpret. - Send the result statements in
Normalmode only.completedmust carryresult.completion: trueand aduration;passedandfailedcarryresult.successand aduration, and anyresult.score.scaledthey include must sit on the right side ofmasteryScore. Onecompletedand onepassedare allowed per AU per registration; afailedafter apassedis not. InBrowseorReviewmode the AU sends onlyinitializedandterminated. - Send
terminatedwith the sessiondurationas the last statement. After a short grace period of its own choosing, the LMS must reject anything else sent for that session — the cmi5 version of the SCORM rule that nothing afterTerminatecounts.
answered per quiz item, an experienced per page — is "cmi5 allowed": stored in the LRS for your reporting, ignored by the LMS for rollup. That split is how one package gives the LMS its completion column and gives you per-interaction data at the same time.cmi5 vs SCORM vs plain xAPI
| Concern | SCORM 2004 | cmi5 | Plain xAPI |
|---|---|---|---|
| Manifest | imsmanifest.xml | cmi5.xml | None |
| Launchable unit | SCO | AU | Any URL |
| How content connects | Finds API_1484_11 in a parent window | Query params + one-time fetch token | Undefined; usually credentials in the query string |
| Where data goes | The LMS | An LRS the LMS points at | Any LRS |
| Completion rule | Content decides; sequencing can roll up | moveOn in the manifest, evaluated by the LMS | Whatever your reporting infers |
| Bookmark | cmi.suspend_data, ≤ 64,000 chars | State resource, no cap in spec | State resource, no cap in spec |
| Per-interaction data | cmi.interactions.n, often not reported on | Any "allowed" statement | Any statement |
| Runs with no LMS | No | No | Yes |
The decision reduces to one question: does the customer need to import a zip and see completion in their own LMS reports? If no, plain xAPI is simpler. If yes and they only need completion, score, and pass/fail, SCORM is the safest import. If yes and you also want statement-level data, cmi5 — provided the platform supports it, which is the next section. The wider guide is SCORM vs cmi5 vs xAPI.
Checking whether a platform really supports it
"Supports cmi5" on a feature list can mean anything from a full implementation to "accepts the zip". Because the handshake is fixed, you can test it in an afternoon with a one-AU package and browser developer tools. Each check that fails tells you which half of the platform is missing.
- Import the manifest above. If the platform rejects it, look for a validation message that names the XSD. A platform that accepts any zip without reading
cmi5.xmlhas not implemented cmi5 import and will not know what to launch. - Launch and read the URL in the address bar or network log. All five parameters must be present. Missing
fetch— withauthin its place — means query-string xAPI launch, not cmi5. - POST the fetch URL twice. The first response is the token; the second should be an
error-codeobject. If the second call also returns a token, the platform has skipped the one-time rule and the launch credential is replayable. - GET
LMS.LaunchData. ConfirmmoveOnandmasteryScorematch your manifest and thatcontextTemplatecontains aregistration. If the document is absent, the AU has no sanctioned way to know the mastery score. - Send
passedwith a scaled score belowmasteryScore. That statement breaks a MUST in the specification. A platform that marks the AU satisfied on it is not comparing scores to the manifest at all. - Send a valid
completedandpassed, thenterminated, and check two places: the LRS should hold asatisfiedstatement from the LMS with the AU as its object, and the LMS report should show the unit complete. One without the other means rollup is not wired to the statements. - Send a
passedstatement a minute afterterminated. The LMS must reject statements for the session once its grace period has elapsed. If the latepassedflips the record, the session boundary is not enforced.
ADL's open-source cmi5 CATAPULT project includes an LMS conformance test suite that automates most of this, plus a reference player and example courses that exercise the AU side. Apply the same discipline as testing a SCORM package before upload, because a cmi5 failure looks identical to a learner: the course runs, and the LMS shows nothing.
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.