Skip to main content
DocsIntegration GuidesCMI5 Integration
Back to docs

CMI5 Integration

cmi5 registration, launch, session tracking

integration
cmi5-integration

cmi5 Integration Guide

This guide walks system administrators through integrating Creatiq H5P content with cmi5-compliant systems, enabling standardized content launch and xAPI-based learning analytics.


1. Overview

What is cmi5?

cmi5 is an xAPI profile that defines a standardized way to launch, track, and score e-learning content. It builds on top of the Experience API (xAPI) specification by adding:

  • A defined launch mechanism with URL parameters
  • A fetch endpoint for secure xAPI authentication
  • Predefined xAPI verbs for lifecycle tracking (initialized, completed, passed, failed, etc.)
  • A structured scoring model

How Creatiq Supports cmi5

Creatiq implements the cmi5 launch protocol for its H5P content library. This allows any cmi5-compliant LMS or content player to:

  1. Register a learner for a specific H5P content item.
  2. Launch the content in a browser with cmi5 parameters.
  3. Track the learner's session status (initialized, launched, completed, passed, failed, abandoned, waived, terminated).
  4. Record scores with the standard scaled/raw/min/max model.
  5. Send xAPI statements to Creatiq's xAPI endpoint using the cmi5 verb set.

cmi5 integration requires the Premium plan and the cmi5-launch feature flag.


2. Registration

Before a learner can launch content, you must register the content-learner combination.

Prerequisites

RequirementDetail
Creatiq planPremium or Enterprise
Feature flagcmi5-launch enabled for your tenant
Content IDA valid H5P content identifier in Creatiq
Actor accountAn xAPI Agent account with homePage and name

Register Content

POST /api/cmi5/register
Authorization: Bearer <api-token>
Content-Type: application/json

{
  "contentId": "h5p-content-abc123",
  "learnerId": "learner-456",
  "actorAccount": {
    "homePage": "https://lms.example.com",
    "name": "learner-456"
  }
}

Validation constraints:

FieldTypeConstraints
contentIdstring1-500 characters
learnerIdstring1-255 characters
actorAccount.homePagestringValid URL, max 500 characters
actorAccount.namestring1-255 characters

Response:

{
  "success": true,
  "data": {
    "id": "reg-uuid-1234",
    "contentId": "h5p-content-abc123",
    "learnerId": "learner-456",
    "actorAccount": {
      "homePage": "https://lms.example.com",
      "name": "learner-456"
    },
    "status": "initialized",
    "sessionId": null,
    "score": null,
    "launchMode": "Normal",
    "createdAt": "2026-03-25T10:00:00.000Z",
    "updatedAt": "2026-03-25T10:00:00.000Z"
  }
}

The registration is uniquely keyed on (contentId, learnerId). If the same combination is registered again, the existing record is returned with an updated timestamp (upsert behavior).


3. Launch Flow

Step 1: Generate a Launch URL

GET /api/cmi5/launch/<registrationId>
Authorization: Bearer <api-token>

Response:

{
  "success": true,
  "data": {
    "launchUrl": "https://creatiq.example.com/h5p/play/h5p-content-abc123?endpoint=...&fetch=...&registration=...&activityId=...&actor=..."
  }
}

Step 2: Open the Launch URL

Redirect the learner's browser to the launchUrl. This opens the H5P content player with the cmi5 parameters embedded in the query string.

What Happens Internally

When a launch URL is generated, the following occurs:

  1. The registration record is looked up by ID.
  2. A unique fetch token is generated (UUID, valid for 1 hour).
  3. A unique session ID is created and stored on the registration.
  4. The registration status is updated to launched.
  5. The launch URL is constructed with the following query parameters:
ParameterValueDescription
endpointhttps://creatiq.example.com/api/xapi/statementsxAPI statement endpoint
fetchhttps://creatiq.example.com/api/cmi5/fetch/<token>One-time fetch URL for auth
registration<registrationId>The cmi5 registration UUID
activityIdhttps://creatiq.example.com/h5p/content/<contentId>Activity IRI
actorJSON-encoded xAPI AgentLearner identity

Step 3: Fetch Token Exchange

When the content (Assignable Unit) loads, it must call the fetch URL to obtain an xAPI authentication token:

POST /api/cmi5/fetch/<fetchToken>

This endpoint:

  1. Validates the fetch token (single-use, 1-hour expiry).
  2. Invalidates the fetch token so it cannot be reused.
  3. Returns a JWT auth-token valid for 1 hour.

Response:

{
  "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6..."
}

The auth token contains:

{
  "registrationId": "<uuid>",
  "purpose": "cmi5-xapi-auth"
}

The content player uses this token as a Bearer token in the Authorization header when sending xAPI statements to the endpoint URL.

Complete Launch Sequence Diagram

LMS/App                   Creatiq API              H5P Player           xAPI Endpoint
  |                           |                        |                      |
  | 1. POST /api/cmi5/register                         |                      |
  |-------------------------->|                        |                      |
  | 2. Registration created   |                        |                      |
  |<--------------------------|                        |                      |
  |                           |                        |                      |
  | 3. GET /api/cmi5/launch/<id>                       |                      |
  |-------------------------->|                        |                      |
  | 4. Launch URL returned    |                        |                      |
  |<--------------------------|                        |                      |
  |                           |                        |                      |
  | 5. Redirect learner to launch URL                  |                      |
  |----------------------------------------------->    |                      |
  |                           |                        |                      |
  |                           | 6. POST /api/cmi5/fetch/<token>               |
  |                           |<-----------------------|                      |
  |                           | 7. Return auth-token   |                      |
  |                           |----------------------->|                      |
  |                           |                        |                      |
  |                           |                        | 8. POST xAPI statements
  |                           |                        |--------------------->|
  |                           |                        |                      |

4. Session Tracking

Session Statuses

Each cmi5 registration tracks the learner's progress through a defined set of statuses:

StatusDescription
initializedRegistration created, content not yet launched
launchedContent has been launched (launch URL generated)
completedLearner finished the content
passedLearner passed the content (score meets threshold)
failedLearner failed the content
abandonedLearner left without completing
waivedContent was waived (skipped by admin/instructor)
terminatedSession was explicitly terminated

Get Session Status

GET /api/cmi5/sessions/<registrationId>
Authorization: Bearer <api-token>

Response:

{
  "success": true,
  "data": {
    "id": "reg-uuid-1234",
    "contentId": "h5p-content-abc123",
    "learnerId": "learner-456",
    "actorAccount": {
      "homePage": "https://lms.example.com",
      "name": "learner-456"
    },
    "status": "completed",
    "sessionId": "session-uuid-789",
    "score": {
      "scaled": 0.85,
      "raw": 85,
      "min": 0,
      "max": 100
    },
    "launchMode": "Normal",
    "createdAt": "2026-03-25T10:00:00.000Z",
    "updatedAt": "2026-03-25T10:30:00.000Z"
  }
}

Update Session Status

For internal or service-to-service use, you can update a session's status and score:

PUT /api/cmi5/sessions/<registrationId>
Authorization: Bearer <api-token>
Content-Type: application/json

{
  "status": "completed",
  "score": {
    "scaled": 0.85,
    "raw": 85,
    "min": 0,
    "max": 100
  }
}

Validation constraints:

FieldTypeConstraints
statusenumOne of: initialized, launched, completed, passed, failed, abandoned, waived, terminated
score.scalednumberOptional, 0.0 to 1.0
score.rawnumberOptional
score.minnumberOptional
score.maxnumberOptional

When a score is provided, it is merged with any existing score (existing fields are preserved if not overwritten).

Launch Modes

cmi5 defines three launch modes:

ModeDescription
NormalStandard learning mode (default). Statements are recorded.
BrowsePreview mode. The learner can explore content without recording results.
ReviewReview mode. The learner revisits completed content.

5. xAPI Statements

Statement Endpoint

The cmi5 content player sends xAPI statements to:

POST /api/xapi/statements
Authorization: Bearer <cmi5-auth-token>

The auth-token obtained from the fetch endpoint is used as the Bearer token.

cmi5 Verbs

Creatiq recognizes and processes the following cmi5-defined xAPI verbs:

VerbIRIDescription
Initializedhttp://adlnet.gov/expapi/verbs/initializedContent was loaded and ready
Completedhttp://adlnet.gov/expapi/verbs/completedLearner completed the content
Passedhttp://adlnet.gov/expapi/verbs/passedLearner achieved a passing score
Failedhttp://adlnet.gov/expapi/verbs/failedLearner did not achieve a passing score
Abandonedhttps://w3id.org/xapi/adl/verbs/abandonedLearner left without completing
Waivedhttps://w3id.org/xapi/adl/verbs/waivedContent requirements were waived
Satisfiedhttps://w3id.org/xapi/adl/verbs/satisfiedObjective or block was satisfied
Terminatedhttp://adlnet.gov/expapi/verbs/terminatedSession was terminated

Statement Context

All cmi5 xAPI statements should include the cmi5 context category in the context.contextActivities.category array:

{
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/completed",
    "display": { "en-US": "completed" }
  },
  "actor": {
    "objectType": "Agent",
    "account": {
      "homePage": "https://lms.example.com",
      "name": "learner-456"
    }
  },
  "object": {
    "id": "https://creatiq.example.com/h5p/content/h5p-content-abc123",
    "objectType": "Activity",
    "definition": {
      "type": "https://w3id.org/xapi/cmi5/activitytype/block"
    }
  },
  "result": {
    "score": {
      "scaled": 0.85,
      "raw": 85,
      "min": 0,
      "max": 100
    },
    "completion": true,
    "success": true
  },
  "context": {
    "registration": "reg-uuid-1234",
    "contextActivities": {
      "category": [
        {
          "id": "https://w3id.org/xapi/cmi5/context/categories/cmi5"
        },
        {
          "id": "https://w3id.org/xapi/cmi5/context/categories/moveon"
        }
      ]
    }
  }
}

cmi5 Context Constants

ConstantValue
Activity Typehttps://w3id.org/xapi/cmi5/activitytype/block
Context Categoryhttps://w3id.org/xapi/cmi5/context/categories/cmi5
MoveOn Categoryhttps://w3id.org/xapi/cmi5/context/categories/moveon

6. Configuration

Environment Variables

VariableRequiredDescription
JWT_SECRETYesSecret key for signing cmi5 auth tokens
NEXT_PUBLIC_APP_URLYesPublic URL of the Creatiq application

Feature Flags

FlagRequired For
cmi5-launchContent registration, launch URL generation, and session status endpoints

Endpoint Reference

MethodPathAuthDescription
POST/api/cmi5/registerBearer token + cmi5-launchRegister content for a learner
GET/api/cmi5/launch/:registrationIdBearer token + cmi5-launchGenerate a launch URL
POST/api/cmi5/fetch/:tokenNone (token in URL)Exchange fetch token for xAPI auth token
GET/api/cmi5/sessions/:registrationIdBearer token + cmi5-launchGet session status
PUT/api/cmi5/sessions/:registrationIdBearer tokenUpdate session status and score

Database

The cmi5 integration uses one database table (auto-created on startup):

TablePurpose
cmi5_registrationsStores content-learner registrations, session state, and scores

Schema:

ColumnTypeDescription
idUUIDPrimary key (auto-generated)
content_idVARCHAR(500)H5P content identifier
learner_idVARCHAR(255)Learner identifier
actor_accountJSONBxAPI Agent account (homePage, name)
statusVARCHAR(50)Current session status (default: initialized)
session_idVARCHAR(255)Session UUID (set on launch)
scoreJSONBScore object (scaled, raw, min, max)
launch_modeVARCHAR(20)Launch mode (default: Normal)
created_atTIMESTAMPRecord creation time
updated_atTIMESTAMPLast update time

Unique constraint: (content_id, learner_id) -- one registration per content-learner pair.

Troubleshooting

SymptomCauseSolution
403 on registration/launchFeature flag cmi5-launch not enabledEnable the feature for your tenant
"JWT_SECRET environment variable is required"Missing secretSet JWT_SECRET in your environment
"Invalid or expired fetch token"Token was already used or expiredGenerate a new launch URL (each fetch token is single-use, 1-hour expiry)
"Registration not found"Invalid registration IDVerify the registration was created and use the correct UUID
xAPI statements rejected (401)Auth token expired or invalidRe-launch the content to get a fresh fetch token and auth token
Duplicate registration returns existing recordExpected upsert behaviorThe (contentId, learnerId) pair is unique; re-registering updates the timestamp
Back to docsdocs/product/integration/cmi5-integration.md