What is cmi5? The package format that carries xAPI

What is cmi5? A zip with a cmi5.xml manifest the LMS imports, whose content reports xAPI to an LRS. Manifest, assignable units, launch handshake, testing.

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.)

SELF-CONTAINED fire-safety.zip ├─ cmi5.xml ← read first ├─ module-1/ │ ├─ index.html ← the AU <url> │ └─ assets/… └─ module-2/ └─ index.html MANIFEST-ONLY fire-safety.zip └─ cmi5.xml your server https://… <url>https://content.example.org/ fire-safety/module-1/</url> Both import. The LMS never inspects the content.
A cmi5 zip is a manifest plus optional content. The AU 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.

AttributeValuesWhat it controls
moveOnPassed, Completed, CompletedAndPassed, CompletedOrPassed, NotApplicableWhich statement(s) from the AU make the LMS mark it satisfied. NotApplicable means it is satisfied on launch.
masteryScoreDecimal 0–1, optionalThe 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.
launchMethodAnyWindow, OwnWindowWhether 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:

LMS AU LRS 1 · statement: launched 2 · open url?endpoint&fetch&actor&registration&activityId 3 · POST fetch URL → {"auth-token":…} (once only) 4 · GET state LMS.LaunchData 5 · statement: initialized 6 · completed / passed / failed 7 · statement: terminated (last) 8 · LMS evaluates moveOn → satisfied
The LMS and the AU never talk directly after launch; the LRS is the only channel between them.

Step by step, from the AU's side:

  1. Parse the launch URL. Five query parameters arrive: endpoint (the LRS base URL), fetch (a URL), actor (a JSON Agent, always with an account identifier under cmi5), registration (a UUID), and activityId (the AU's id from the manifest).
  2. POST to the fetch URL with an empty body. The response is {"auth-token": "…"}; use it as Authorization: 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.
  3. GET the launch data. GET <endpoint>/activities/state?stateId=LMS.LaunchData&activityId=…&agent=…&registration=… returns JSON with launchMode (Normal, Browse, or Review), moveOn, masteryScore, an optional returnURL, any manifest launchParameters, and a contextTemplate.
  4. Send initialized first, and once. Every cmi5-defined statement is built from the contextTemplate: it fixes context.registration, a sessionid extension, and the category activity https://w3id.org/xapi/cmi5/context/categories/cmi5 that marks a statement as one the LMS should interpret.
  5. Send the result statements in Normal mode only. completed must carry result.completion: true and a duration; passed and failed carry result.success and a duration, and any result.score.scaled they include must sit on the right side of masteryScore. One completed and one passed are allowed per AU per registration; a failed after a passed is not. In Browse or Review mode the AU sends only initialized and terminated.
  6. Send terminated with the session duration as 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 after Terminate counts.
The AU can send other statements too. Anything without the cmi5 category — an 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

ConcernSCORM 2004cmi5Plain xAPI
Manifestimsmanifest.xmlcmi5.xmlNone
Launchable unitSCOAUAny URL
How content connectsFinds API_1484_11 in a parent windowQuery params + one-time fetch tokenUndefined; usually credentials in the query string
Where data goesThe LMSAn LRS the LMS points atAny LRS
Completion ruleContent decides; sequencing can roll upmoveOn in the manifest, evaluated by the LMSWhatever your reporting infers
Bookmarkcmi.suspend_data, ≤ 64,000 charsState resource, no cap in specState resource, no cap in spec
Per-interaction datacmi.interactions.n, often not reported onAny "allowed" statementAny statement
Runs with no LMSNoNoYes

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.

  1. 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.xml has not implemented cmi5 import and will not know what to launch.
  2. Launch and read the URL in the address bar or network log. All five parameters must be present. Missing fetch — with auth in its place — means query-string xAPI launch, not cmi5.
  3. POST the fetch URL twice. The first response is the token; the second should be an error-code object. If the second call also returns a token, the platform has skipped the one-time rule and the launch credential is replayable.
  4. GET LMS.LaunchData. Confirm moveOn and masteryScore match your manifest and that contextTemplate contains a registration. If the document is absent, the AU has no sanctioned way to know the mastery score.
  5. Send passed with a scaled score below masteryScore. 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.
  6. Send a valid completed and passed, then terminated, and check two places: the LRS should hold a satisfied statement 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.
  7. Send a passed statement a minute after terminated. The LMS must reject statements for the session once its grace period has elapsed. If the late passed flips 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.

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