Skip to main content
DocsAPI ReferencexAPI & Analytics API
Back to docs

xAPI & Analytics API

xAPI statements, H5P events, class/student analytics

api
xapi-analytics

xAPI & Analytics API Reference

xAPI statement storage, H5P event handling, learner progress tracking, and multi-level analytics (content, student, class). All xAPI data is stored in PostgreSQL with JSONB columns for flexible querying.


xAPI Statement Endpoints

Base path: /api/xapi

POST /api/xapi/statements

Store one or more xAPI statements.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateNone

Description

Accepts a single xAPI statement or an array of statements. Each statement's actor is enriched with the authenticated user's account information (overwriting actor.account with { homePage, name: userId }). Statements are validated for required fields: actor must have mbox or account, verb.id is required, object.id is required. If no id is provided, a UUID is auto-generated. If no timestamp is provided, the current time is used. Duplicate statement IDs are silently ignored (ON CONFLICT DO NOTHING).

Each stored statement emits a 'statement' event on the xAPI service EventEmitter, enabling downstream listeners (e.g., AGS score passback).

Request

Single statement:

{
  "actor": {
    "objectType": "Agent",
    "account": { "homePage": "https://example.com", "name": "user-1" }
  },
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/completed",
    "display": { "en-US": "completed" }
  },
  "object": {
    "objectType": "Activity",
    "id": "https://app.creatiq.com/h5p/content/abc123",
    "definition": {
      "type": "http://adlnet.gov/expapi/activities/assessment",
      "name": { "en-US": "Biology Quiz" }
    }
  },
  "result": {
    "score": { "scaled": 0.85, "raw": 85, "max": 100 },
    "success": true,
    "completion": true,
    "duration": "PT120S"
  },
  "context": {
    "platform": "EduAgentic H5P",
    "language": "en"
  }
}

Or an array of statements: [ { ... }, { ... } ]

Response

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

Errors

StatusErrorCondition
401UnauthorizedMissing or invalid JWT
500Failed to store statementactor missing mbox/account, verb.id missing, or object.id missing

POST /api/xapi/h5p-event

Handle H5P xAPI events in simplified format.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateNone

Description

A convenience endpoint that accepts a simplified H5P event payload and converts it to a full xAPI statement. The verb string is mapped to a standard xAPI verb IRI:

Verb StringxAPI Verb IRI
attemptedhttp://adlnet.gov/expapi/verbs/attempted
answeredhttp://adlnet.gov/expapi/verbs/answered
completedhttp://adlnet.gov/expapi/verbs/completed
passedhttp://adlnet.gov/expapi/verbs/passed
failedhttp://adlnet.gov/expapi/verbs/failed
interactedhttp://adlnet.gov/expapi/verbs/interacted
progressedhttp://adlnet.gov/expapi/verbs/progressed
(unknown)Falls back to interacted

The generated statement uses:

  • Actor: authenticated user's account
  • Object: {baseUrl}/h5p/content/{contentId} with activity type assessment
  • Context: platform "EduAgentic H5P", language "en"
  • Duration: converted to ISO 8601 format (PT{seconds}S)

Request

{
  "contentId": "abc123",
  "verb": "completed",
  "score": {
    "scaled": 0.85,
    "raw": 85,
    "max": 100
  },
  "success": true,
  "completion": true,
  "duration": 120,
  "response": "selected-choice-2"
}
FieldTypeRequiredDescription
contentIdstringYesH5P content identifier
verbstringYesVerb name (see mapping above)
scoreobjectNoScore with scaled, raw, max
successbooleanNoWhether the attempt was successful
completionbooleanNoWhether the content was completed
durationnumberNoDuration in seconds
responsestringNoLearner response data

Response

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

Errors

StatusErrorCondition
400Missing required fields: contentId, verbMissing required fields
401UnauthorizedMissing or invalid JWT

GET /api/xapi/statements

Query stored xAPI statements with filters.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateNone

Description

Retrieves xAPI statements matching the provided filters. Results are ordered by timestamp descending. All filter parameters are optional; omitting all filters returns all statements (up to limit). Actor matching checks both actor.account.name and actor.mbox.

Query Parameters

ParamTypeRequiredDescription
actorIdstringNoFilter by actor account name or mbox
verbIdstringNoFilter by verb IRI
objectIdstringNoFilter by object/activity ID
sincestring (ISO 8601)NoOnly statements after this timestamp
untilstring (ISO 8601)NoOnly statements before this timestamp
limitnumberNoMaximum number of results

Response

{
  "success": true,
  "data": {
    "statements": [
      {
        "id": "uuid",
        "actor": { "objectType": "Agent", "account": { "homePage": "...", "name": "..." } },
        "verb": { "id": "http://adlnet.gov/expapi/verbs/completed", "display": { "en-US": "completed" } },
        "object": { "objectType": "Activity", "id": "..." },
        "result": { "score": { "scaled": 0.85 }, "success": true, "completion": true },
        "context": { "platform": "EduAgentic H5P" },
        "timestamp": "2025-01-15T11:30:00.000Z"
      }
    ]
  }
}

Errors

StatusErrorCondition
401UnauthorizedMissing or invalid JWT
500Failed to query statementsDatabase error

xAPI Progress Endpoints

GET /api/xapi/progress/:contentId

Get the authenticated user's progress on a specific content item.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateNone

Path Parameters

ParamTypeDescription
contentIdstringContent/activity identifier

Response

{
  "success": true,
  "data": {
    "userId": "user-12345",
    "contentId": "abc123",
    "attempts": 3,
    "bestScore": 92,
    "lastScore": 0,
    "completed": true,
    "passed": true,
    "totalDuration": 0,
    "lastAttemptAt": "2025-01-15T11:30:00.000Z"
  }
}

When no progress exists:

{
  "success": true,
  "data": {
    "userId": "user-12345",
    "contentId": "abc123",
    "attempts": 0,
    "bestScore": 0,
    "lastScore": 0,
    "completed": false,
    "passed": false,
    "totalDuration": 0,
    "message": "No progress recorded yet"
  }
}

GET /api/xapi/progress

Get all content progress for the authenticated user.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateNone

Response

{
  "success": true,
  "data": {
    "progress": [
      {
        "userId": "user-12345",
        "contentId": "abc123",
        "attempts": 3,
        "bestScore": 92,
        "lastScore": 0,
        "completed": true,
        "passed": true,
        "totalDuration": 0,
        "lastAttemptAt": "2025-01-15T11:30:00.000Z"
      },
      {
        "userId": "user-12345",
        "contentId": "def456",
        "attempts": 1,
        "bestScore": 60,
        "lastScore": 0,
        "completed": false,
        "passed": false,
        "totalDuration": 0,
        "lastAttemptAt": "2025-01-14T09:00:00.000Z"
      }
    ]
  }
}

xAPI Content & User Analytics

GET /api/xapi/analytics/content/:contentId

Get aggregate analytics for a specific content item.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateNone

Description

Computes aggregate metrics across all learners for a content item. Scores are calculated from result.score.scaled on completed verb statements. Pass rate is passed / completed * 100.

Path Parameters

ParamTypeDescription
contentIdstringContent/activity identifier

Response

{
  "success": true,
  "data": {
    "contentId": "abc123",
    "totalAttempts": 150,
    "totalCompletions": 120,
    "averageScore": 78.5,
    "averageDuration": 0,
    "passRate": 85.0,
    "lastUpdated": "2025-01-15T11:30:00.000Z"
  }
}

When no data exists:

{
  "success": true,
  "data": {
    "contentId": "abc123",
    "totalAttempts": 0,
    "totalCompletions": 0,
    "averageScore": 0,
    "averageDuration": 0,
    "passRate": 0,
    "message": "No analytics data available yet"
  }
}

GET /api/xapi/analytics/user

Get analytics summary for the authenticated user.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateNone

Description

Returns a learner analytics summary: total content attempted/completed, average score, and identification of strong areas (score >= 80) and weak areas (score > 0 and < 50).

Response

{
  "success": true,
  "data": {
    "userId": "user-12345",
    "totalContentsAttempted": 15,
    "totalContentsCompleted": 12,
    "averageScore": 76.3,
    "strongAreas": ["content-a", "content-b"],
    "weakAreas": ["content-x"],
    "learningTime": 0
  }
}

Analytics Dashboard Endpoints

Base path: /api/analytics

These endpoints power the teacher analytics dashboard and require the analytics-dashboard feature gate.

GET /api/analytics/class-overview

Get aggregate analytics for a teacher's class.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateanalytics-dashboard

Description

Returns a class-level overview including total students, weekly active count, average completion rate, top-performing content (up to 5), weakest topics (score < 60%, up to 5), and a 30-day activity heatmap. The query scopes to content that the authenticated teacher has interacted with (attempted).

Response

{
  "success": true,
  "data": {
    "totalStudents": 45,
    "activeThisWeek": 38,
    "averageCompletionRate": 72,
    "topPerformingContent": [
      { "contentId": "https://app.creatiq.com/h5p/content/abc", "title": "Cell Biology Quiz", "avgScore": 92 },
      { "contentId": "https://app.creatiq.com/h5p/content/def", "title": "Math Basics", "avgScore": 88 }
    ],
    "weakestTopics": [
      { "topic": "Organic Chemistry", "avgScore": 42, "studentCount": 30 },
      { "topic": "Calculus II", "avgScore": 38, "studentCount": 25 }
    ],
    "activityHeatmap": [
      { "date": "2025-01-01", "activityCount": 120 },
      { "date": "2025-01-02", "activityCount": 95 }
    ]
  }
}

Errors

StatusErrorCondition
401UnauthorizedMissing or invalid JWT
403Feature not availableanalytics-dashboard not enabled

GET /api/analytics/content/:contentId

Get detailed analytics for a specific content item.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateanalytics-dashboard

Description

Returns detailed per-content analytics including attempt counts, unique student count, average score, completion rate, average duration, and a per-question breakdown showing correct rates and attempt counts. Question breakdown is derived from answered verb statements where result.response is present.

Path Parameters

ParamTypeDescription
contentIdstringContent/activity identifier (min 1 char)

Response

{
  "success": true,
  "data": {
    "contentId": "abc123",
    "totalAttempts": 150,
    "uniqueStudents": 45,
    "averageScore": 78,
    "completionRate": 80,
    "averageDuration": 145,
    "questionBreakdown": [
      { "questionId": "q1-choice-a", "correctRate": 92, "avgAttempts": 1 },
      { "questionId": "q2-choice-b", "correctRate": 45, "avgAttempts": 3 },
      { "questionId": "q3-fill-blank", "correctRate": 68, "avgAttempts": 2 }
    ]
  }
}

Errors

StatusErrorCondition
400Validation error: ...Empty contentId parameter
401UnauthorizedMissing or invalid JWT
403Feature not availableanalytics-dashboard not enabled

GET /api/analytics/student/:studentId

Get analytics for a specific student.

PropertyValue
AuthJWT Bearer token (authMiddleware)
Feature gateanalytics-dashboard

Description

Returns a student's overall score, completed activity count, recent activity (up to 20 most recent xAPI statements), and per-topic performance breakdown.

Path Parameters

ParamTypeDescription
studentIdstringStudent/learner identifier (min 1 char)

Response

{
  "success": true,
  "data": {
    "studentId": "user-12345",
    "overallScore": 76,
    "completedActivities": 12,
    "recentActivity": [
      {
        "id": "uuid",
        "actor": { "objectType": "Agent", "account": { "homePage": "...", "name": "user-12345" } },
        "verb": { "id": "http://adlnet.gov/expapi/verbs/completed" },
        "object": { "id": "https://app.creatiq.com/h5p/content/abc123" },
        "result": { "score": { "scaled": 0.85 } },
        "timestamp": "2025-01-15T11:30:00.000Z"
      }
    ],
    "topicPerformance": [
      { "topic": "Cell Biology Quiz", "score": 92 },
      { "topic": "Math Basics", "score": 88 },
      { "topic": "Organic Chemistry", "score": 42 }
    ]
  }
}

Errors

StatusErrorCondition
400Validation error: ...Empty studentId parameter
401UnauthorizedMissing or invalid JWT
403Feature not availableanalytics-dashboard not enabled

xAPI Data Types

XAPIStatement

interface XAPIStatement {
  id?: string;                    // UUID, auto-generated if omitted
  actor: XAPIActor;               // Who performed the action
  verb: XAPIVerb;                 // What action was performed
  object: XAPIObject;             // What the action was performed on
  result?: XAPIResult;            // Outcome of the action
  context?: XAPIContext;          // Additional context
  timestamp?: string;             // ISO 8601, defaults to now
  stored?: string;                // ISO 8601, set by server
  authority?: XAPIActor;          // Who asserts this statement
  version?: string;               // xAPI version (default: "1.0.3")
}

XAPIActor

interface XAPIActor {
  objectType?: "Agent" | "Group";
  mbox?: string;                  // mailto: IRI
  mbox_sha1sum?: string;
  openid?: string;
  account?: {
    homePage: string;             // Account system URL
    name: string;                 // Account identifier
  };
  name?: string;                  // Display name
}

XAPIResult

interface XAPIResult {
  score?: {
    scaled?: number;              // -1 to 1, normalized score
    raw?: number;                 // Actual score
    min?: number;                 // Minimum possible
    max?: number;                 // Maximum possible
  };
  success?: boolean;
  completion?: boolean;
  response?: string;              // Learner response data
  duration?: string;              // ISO 8601 duration (e.g., "PT120S")
}

Database Table

xapi_statements

ColumnTypeDescription
idUUID (PK)Statement ID
actorJSONBxAPI actor object
verbJSONBxAPI verb object
objectJSONBxAPI activity/object
resultJSONBScore, success, completion, duration
contextJSONBPlatform, language, registration
timestampTIMESTAMPTZWhen the event occurred
storedTIMESTAMPTZWhen stored in database
authorityJSONBAsserting authority
versionVARCHAR(20)xAPI spec version
full_statementJSONBComplete original statement

Indexes:

  • idx_xapi_actor_name -- GIN index on actor->'account'->'name'
  • idx_xapi_verb_id -- B-tree on verb->>'id'
  • idx_xapi_object_id -- B-tree on object->>'id'
  • idx_xapi_timestamp -- B-tree on timestamp DESC

Standard Verb IRIs

ConstantIRI
ATTEMPTEDhttp://adlnet.gov/expapi/verbs/attempted
ANSWEREDhttp://adlnet.gov/expapi/verbs/answered
COMPLETEDhttp://adlnet.gov/expapi/verbs/completed
PASSEDhttp://adlnet.gov/expapi/verbs/passed
FAILEDhttp://adlnet.gov/expapi/verbs/failed
INTERACTEDhttp://adlnet.gov/expapi/verbs/interacted
PROGRESSEDhttp://adlnet.gov/expapi/verbs/progressed
Back to docsdocs/product/api/xapi-analytics.md