Skip to main content
DocsIntegration GuidesxAPI Integration
Back to docs

xAPI Integration

Statement format, verbs, LRS configuration

integration
xapi-integration

xAPI Integration Guide

Overview

Creatiq includes built-in xAPI (Experience API) support that automatically tracks learner interactions with H5P content. Every time a user plays, answers, completes, or fails an H5P activity, Creatiq generates xAPI statements conforming to the xAPI 1.0.3 specification and stores them in PostgreSQL.

Key capabilities:

  • Automatic statement generation from H5P player events (no manual instrumentation needed)
  • 7 supported verbs covering the full learning interaction lifecycle
  • Built-in analytics with content-level, learner-level, and class-level aggregations
  • Statement querying API with filters for actor, verb, object, and time range
  • Event emitter for real-time forwarding to external LRS systems

All xAPI endpoints require authentication via Bearer token (Authorization: Bearer <token>).


Statement Format

Creatiq xAPI statements follow the standard structure:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "actor": {
    "objectType": "Agent",
    "account": {
      "homePage": "https://creatiq.app",
      "name": "user-uuid-here"
    }
  },
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/completed",
    "display": { "en-US": "completed" }
  },
  "object": {
    "objectType": "Activity",
    "id": "https://creatiq.app/h5p/content/content-id-here",
    "definition": {
      "type": "http://adlnet.gov/expapi/activities/assessment"
    }
  },
  "result": {
    "score": {
      "scaled": 0.85,
      "raw": 17,
      "max": 20
    },
    "success": true,
    "completion": true,
    "duration": "PT120S",
    "response": "answer-data"
  },
  "context": {
    "platform": "EduAgentic H5P",
    "language": "en"
  },
  "timestamp": "2026-03-25T10:30:00.000Z",
  "version": "1.0.3"
}

Actor

All actors use the account identifier type. The homePage is derived from the NEXT_PUBLIC_BASE_URL environment variable (defaults to https://eduagentic.ai), and name is set to the authenticated user's UUID. When statements are submitted via POST /api/xapi/statements, the actor's account is automatically enriched from the authenticated session.

Verb

Each verb includes an id (IRI) and a display map. See the Supported Verbs section below.

Object

The object id follows the pattern {BASE_URL}/h5p/content/{contentId}. The definition.type is set to http://adlnet.gov/expapi/activities/assessment for all H5P content.

Result

The result object is optional and contains:

FieldTypeDescription
score.scalednumber (0-1)Normalized score
score.rawnumberRaw score value
score.maxnumberMaximum possible score
score.minnumberMinimum possible score
successbooleanWhether the learner succeeded
completionbooleanWhether the activity was completed
durationstringISO 8601 duration (e.g., PT120S)
responsestringLearner's response data

Context

The context object includes:

FieldTypeDescription
platformstringAlways "EduAgentic H5P"
languagestringContent language code
registrationstringRegistration UUID (optional)
contextActivitiesobjectParent, grouping, category activities (optional)

Supported Verbs

Creatiq recognizes and maps the following 7 xAPI verbs:

VerbIRIDescription
attemptedhttp://adlnet.gov/expapi/verbs/attemptedLearner started an activity
answeredhttp://adlnet.gov/expapi/verbs/answeredLearner submitted an answer to a question
completedhttp://adlnet.gov/expapi/verbs/completedLearner finished the activity
passedhttp://adlnet.gov/expapi/verbs/passedLearner met the passing criteria
failedhttp://adlnet.gov/expapi/verbs/failedLearner did not meet the passing criteria
interactedhttp://adlnet.gov/expapi/verbs/interactedLearner interacted with the content (generic)
progressedhttp://adlnet.gov/expapi/verbs/progressedLearner made progress within the activity

When an unrecognized verb is received from H5P, it falls back to interacted.


Auto-Generated Statements

H5P content types automatically emit xAPI events through the H5P runtime. When a user plays content via the Creatiq embed player (/embed/{contentId}), the player intercepts these events and:

  1. Extracts the verb name from the xAPI verb IRI (last path segment)
  2. Parses the result object (score, success, completion, duration)
  3. Sends the data to POST /api/xapi/h5p-event with the authenticated token
  4. Simultaneously forwards the raw statement to the parent window via postMessage (for SDK consumers)

H5P Events That Generate Statements

H5P Content TypeEvents Generated
Multiple Choiceattempted, answered, completed, passed/failed
True/Falseattempted, answered, completed, passed/failed
Fill in the Blanksattempted, answered, completed, passed/failed
Drag and Dropattempted, interacted, completed, passed/failed
Interactive Videoattempted, interacted, progressed, answered, completed
Course Presentationattempted, progressed, answered, completed
Question Setattempted, answered, completed, passed/failed
Summaryattempted, answered, completed
Essayattempted, answered, completed
Dialog Cardsattempted, interacted, completed

SDK postMessage Events

When content is embedded via the SDK <CreatiqPlayer> component or a raw iframe, xAPI statements are also forwarded to the parent window:

// Message format sent to parent window
{
  type: 'creatiq:xapi',
  contentId: 'abc123',
  statement: { /* full xAPI statement */ }
}

Listen for these in your host application:

window.addEventListener('message', (event) => {
  if (event.data?.type === 'creatiq:xapi') {
    const { contentId, statement } = event.data;
    // Forward to your own LRS, analytics pipeline, etc.
  }
});

LRS Configuration

Creatiq stores all xAPI statements in its own PostgreSQL database. To forward statements to an external Learning Record Store (LRS), use the XAPIService event emitter on the server side:

Server-Side Forwarding

The xapiService instance emits a statement event every time a statement is successfully stored:

import { xapiService } from './services/xapi';

xapiService.on('statement', async (statement) => {
  // Forward to external LRS
  await fetch('https://your-lrs.example.com/xapi/statements', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Basic ' + btoa('key:secret'),
      'X-Experience-API-Version': '1.0.3',
    },
    body: JSON.stringify(statement),
  });
});

Client-Side Forwarding via SDK

If you are using the <CreatiqPlayer> SDK component, use the onXAPIStatement callback:

<CreatiqPlayer
  contentId="abc123"
  onXAPIStatement={(statement) => {
    // Send to your LRS endpoint
    fetch('/api/lrs/statements', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(statement),
    });
  }}
/>

Supported LRS Platforms

Creatiq xAPI statements are compatible with any LRS that supports xAPI 1.0.3:

  • Learning Locker
  • SCORM Cloud
  • Watershed LRS
  • Yet Analytics
  • Veracity Learning

Querying Statements -- API Endpoints

Store Statements

POST /api/xapi/statements
Authorization: Bearer <token>
Content-Type: application/json

Body: A single statement object or an array of statements.

Response:

{
  "success": true,
  "data": { "ids": ["uuid-1", "uuid-2"] }
}

Store H5P Event (Simplified)

POST /api/xapi/h5p-event
Authorization: Bearer <token>
Content-Type: application/json

Body:

{
  "contentId": "abc123",
  "verb": "completed",
  "score": { "scaled": 0.85, "raw": 17, "max": 20 },
  "success": true,
  "completion": true,
  "duration": 120,
  "response": "answer-data"
}

Required fields: contentId, verb. All other fields are optional.

Response:

{
  "success": true,
  "data": { "id": "generated-uuid" }
}

Query Statements

GET /api/xapi/statements
Authorization: Bearer <token>

Query Parameters:

ParameterTypeDescription
actorIdstringFilter by actor account name or mbox
verbIdstringFilter by verb IRI (e.g., http://adlnet.gov/expapi/verbs/completed)
objectIdstringFilter by object IRI
sinceISO 8601Statements after this timestamp
untilISO 8601Statements before this timestamp
limitnumberMaximum number of statements to return

Response:

{
  "success": true,
  "data": {
    "statements": [ /* array of xAPI statements */ ]
  }
}

Content Analytics

GET /api/xapi/analytics/content/:contentId
Authorization: Bearer <token>

Response:

{
  "success": true,
  "data": {
    "contentId": "abc123",
    "totalAttempts": 150,
    "totalCompletions": 120,
    "averageScore": 78.5,
    "averageDuration": 0,
    "passRate": 85.0,
    "lastUpdated": "2026-03-25T10:30:00.000Z"
  }
}

User Analytics

GET /api/xapi/analytics/user
Authorization: Bearer <token>

Returns aggregated analytics for the authenticated user.

Response:

{
  "success": true,
  "data": {
    "userId": "user-uuid",
    "totalContentsAttempted": 25,
    "totalContentsCompleted": 20,
    "averageScore": 82.3,
    "strongAreas": ["content-id-1", "content-id-2"],
    "weakAreas": ["content-id-3"],
    "learningTime": 0
  }
}

User Progress (Single Content)

GET /api/xapi/progress/:contentId
Authorization: Bearer <token>

Response:

{
  "success": true,
  "data": {
    "userId": "user-uuid",
    "contentId": "abc123",
    "attempts": 3,
    "bestScore": 95.0,
    "lastScore": 0,
    "completed": true,
    "passed": true,
    "totalDuration": 0,
    "lastAttemptAt": "2026-03-25T10:30:00.000Z"
  }
}

User Progress (All Content)

GET /api/xapi/progress
Authorization: Bearer <token>

Response:

{
  "success": true,
  "data": {
    "progress": [
      {
        "userId": "user-uuid",
        "contentId": "abc123",
        "attempts": 3,
        "bestScore": 95.0,
        "lastScore": 0,
        "completed": true,
        "passed": true,
        "totalDuration": 0,
        "lastAttemptAt": "2026-03-25T10:30:00.000Z"
      }
    ]
  }
}

Data Schema

Creatiq stores xAPI statements in the xapi_statements table with the following structure:

ColumnTypeDescription
idUUIDStatement ID (primary key)
actorJSONBActor object
verbJSONBVerb object
objectJSONBActivity object
resultJSONBResult object (nullable)
contextJSONBContext object (nullable)
timestampTIMESTAMPTZStatement timestamp
storedTIMESTAMPTZWhen the statement was stored
authorityJSONBAuthority object (nullable)
versionVARCHAR(20)xAPI version (default: 1.0.3)
full_statementJSONBComplete statement for retrieval

Indexed fields: actor.account.name (GIN), verb.id, object.id, timestamp (DESC).

Duplicate statements (same id) are silently ignored via ON CONFLICT DO NOTHING.

Back to docsdocs/product/integration/xapi-integration.md