The specific problem this guide addresses: your LMS is sending xAPI statements, your LRS endpoint is configured, and statements are either not arriving, arriving with the wrong actor identifier, or arriving but not query able in the way your analytics layer expects. Alternatively, you are planning an LRS deployment and need to choose between an embedded LRS, a standalone LRS, and a multi-LRS statement-forwarding architecture, and the vendor documentation you have does not distinguish between them.
The current authoritative specification is xAPI 2.0, published as IEEE 9274.1.1-2023 on October 10, 2023. It supersedes xAPI 1.0.3 (ADL, September 2016) and introduces contextAgents, contextGroups, and updated concurrency rules for document resources. The LRS conformance test suite for xAPI 2.0 requires passing over 1,400 individual tests. Most production LMS platforms were built against xAPI 1.0.3, a gap that has practical implications for organisations deploying xAPI 2.0-conformant content or LRS platforms.
This guide covers: the xAPI statement model at the level of detail required for LRS configuration decisions; LRS deployment architecture options; a compatibility matrix for enterprise LMS platforms and LRS products; and a step-by-step configuration walkthrough covering endpoints, credential scoping, actor IFI strategy, statement forwarding, and LTI-based LRS integration. Troubleshooting section covers the six most common production failure patterns, sourced from ADL GitHub issues, SCORM.com forums, and community reports.
xAPI Statement Architecture and LRS Communication Model
The xAPI Statement: What the LRS Actually Receives
An xAPI statement is a JSON object representing a discrete learning experience. The minimum valid statement requires three properties, actor, verb, and object. The id field (UUID v4, RFC 4122) SHOULD be generated by the Learning Record Provider (LRP); if omitted, the LRS MUST generate one. The X-Experience-API-Version request header MUST be included on every xAPI HTTP call, its absence is the most common cause of LRS 400 rejections.
xAPI Statement, Annotated Production Example (xAPI 1.0.3 / 2.0 compatible)
// Minimum conformant xAPI 1.0.3 / 2.0 statement
{
“id”: “4b5a9b2e-1234-5678-abcd-9e8f7a6b5c4d”,
“actor”: {
“objectType”: “Agent”,
“account”: {
“homePage”: “https://lms.example.com“,
“name”: “user-id-48291” // IFI: account recommended for enterprise LMS
}
},
“verb”: {
“id”: “http://adlnet.gov/expapi/verbs/completed“,
“display”: { “en-US”: “completed” }
},
“object”: {
“id”: “https://lms.example.com/activities/safety-module-01“,
“objectType”: “Activity”,
“definition”: {
“name”: { “en-US”: “Workplace Safety, Module 1” },
“type”: “http://adlnet.gov/expapi/activities/module“
}
},
“result”: {
“completion”: true,
“success”: true,
“score”: { “scaled”: 0.87, “raw”: 87, “min”: 0, “max”: 100 },
“duration”: “PT22M14S” // ISO 8601 duration, required for cmi5
},
“context”: {
“registration”: “9e8f7a6b-5c4d-3e2f-1a0b-c9d8e7f6a5b4”, // ties to LMS enrolment
“contextActivities”: {
“grouping”: [{ “id”: “https://lms.example.com/courses/safety-2026” }]
}
},
“timestamp”: “2026-03-27T09:14:22.000Z”, // ISO 8601, UTC preferred
“stored”: “2026-03-27T09:14:23.411Z” // set by LRS on receipt
}
Actor Inverse Functional Identifier (IFI) Strategy
The actor’s IFI determines how statements are attributed and queried across systems. xAPI defines four IFI types; choosing the wrong one is the most common cause of identity fragmentation in multi-system LRS deployments. The xAPI spec requires that an Agent include exactly one IFI.
| IFI Type | Format | LMS / Enterprise Use Case | Recommendation |
|---|---|---|---|
| mbox | mailto:j.smith@example.com | Simple, readable, tied to email | Avoid: breaks on email change; PII in LRS |
| mbox_sha1sum | SHA1 hash of mailto: URI | PII-obscured alternative to mbox | Use only if email is the only stable UID |
| openid | HTTPS URI for the user’s OpenID | Federated identity; uncommon in LMS | Uncommon, only if IdP exposes stable URI |
| account | {homePage: LMS_URL, name: user_id} | Maps to LMS internal user ID | RECOMMENDED for enterprise LMS deployments |
For enterprise LMS deployments, always use account IFI with the LMS URL as homePage and the stable internal user ID (not email) as name. This survives email address changes, supports pseudonymisation requirements under GDPR, and maps cleanly to HR system identifiers. Reference: xAPI Spec §2.4.2.3.
LRS Deployment Architecture: Embedded vs Standalone vs Federated
Three patterns cover the majority of enterprise LMS deployments. Choosing the wrong architecture leads to statements stored where they cannot be queried, or duplicated across LRS instances.
- Embedded LRS (LMS-native). The LRS is built into the LMS platform. Docebo, Absorb, and Cornerstone all ship embedded LRS instances. Statements from content launched inside the LMS flow automatically to the embedded LRS. Limitation: the embedded LRS typically has a closed query API, analytics tooling from other vendors cannot read from it without LMS-specific API calls. Use when: all content is launched from a single LMS and reporting is handled within that LMS’s native tools.
- Standalone LRS (external). A dedicated LRS (SCORM Cloud LRS, Watershed, Veracity Learning, Learning Locker / OpenLRS) sits outside the LMS. Content authors configure the LRS endpoint in their authoring tool publish settings. The LMS may or may not be aware of the LRS, it depends on whether the LMS launch parameters include the LRS endpoint. Use when: content is launched from multiple systems; analytics requires cross-LMS aggregation; or the embedded LRS has reporting limitations.
- Federated / Statement Forwarding. The LMS’s embedded LRS is configured to forward statements to a central enterprise LRS. This is the most common architecture in large organisations with multiple LMS instances or content platforms, each system’s LRS forwards to a single authoritative analytics LRS. Statement forwarding is an xAPI 1.0.3 / 2.0 feature: the forwarding LRS sends statements via HTTP POST to the target LRS endpoint. Target LRS credentials must be configured in the forwarding LRS’s forwarding policy.
xAPI 2.0 vs xAPI 1.0.3, What Changes Operationally
| Area | xAPI 1.0.3 (ADL, Sep 2016) | xAPI 2.0 / IEEE 9274.1.1-2023 (Oct 2023) |
|---|---|---|
| Version header value | 1.0.3 | 2.0.0 |
| contextAgents | ✗ Not supported | ✓ New, identifies additional actors in context |
| contextGroups | ✗ Not supported | ✓ New, identifies groups in context |
| Document resource concurrency | ETag / If-Match | Updated: stricter concurrency enforcement |
| Backwards compatibility | 1.0.x are all functionally equivalent | 2.0 LRS must also accept 1.0.3 statements |
| Conformance test count | ~900 tests | 1,400+ tests (ADL test suite) |
| IEEE standard | ✗ No (ADL specification) | ✓ Yes, IEEE open source standard |
| LMS adoption rate (2026) | Dominant, most LMS platforms | Early, Veracity first commercial LRS to pass |
| cmi5 compatibility | ✓ Fully compatible | ✓ Fully compatible (cmi5 profile unchanged) |
Practical implication: in 2026, configure your LRS to accept both xAPI 1.0.3 and 2.0.0 version headers. Most authoring tools still emit 1.0.3 statements. A strict xAPI 2.0-only LRS will reject all existing content until tools update their version header.
LRS and LMS Compatibility Matrix
Standalone LRS Platform Comparison (ADL Conformance Status 2026)
| LRS Platform | xAPI 1.0.3 | xAPI 2.0 | cmi5 | Statement Fwd | LTI | Deployment Options |
|---|---|---|---|---|---|---|
| SCORM Cloud (Rustici) | ✓ ADL cert. | ◑ In progress | ✓ | ✓ | ✓ | Cloud SaaS; free tier available |
| Veracity Learning | ✓ ADL cert. | ✓ First comm. cert. | ✓ | ✓ | ✓ LTI | Cloud SaaS + on-premise |
| Watershed | ✓ ADL cert. | ◑ | ✓ | ✓ | ◑ | Cloud SaaS only |
| Learning Locker (v5) | ✓ | ◑ | ✓ | ✓ | ◑ | Self-hosted open source |
| OpenLRS (Apereo) | ✓ | ◑ | ◑ | ✓ | ✓ LTI | Open source; HE/edu focus |
| ADL LRS (reference) | ✓ | ✓ xAPI 2.0 | ◑ | ◑ | ✗ | Open source; dev/test only |
| Rustici Engine LRS | ✓ ADL cert. | ◑ | ✓ | ✓ | ✓ | Embedded / white-label |
| lrs.io (Veracity) | ✓ | ✓ | ✓ | ✓ | ◑ | Free tier (100MB, 100k stmts) |
ADL cert. = passed ADL conformance test suite. ADL conformant LRS list: adopters.adlnet.gov/products/all/0. cmi5 conformance is tested separately by the cmi5 Working Group (aicc.org). ◑ = partial or in-progress support.
LMS Platform Embedded LRS and xAPI Support (2026)
| LMS Platform | Embedded LRS | Ext. LRS Config | xAPI 1.0.3 | xAPI 2.0 | cmi5 | Statement Forwarding |
|---|---|---|---|---|---|---|
| Docebo | ✓ Internal | ✓ External | ✓ | ◑ | ✓ | Via external LRS config; embed. LRS not queryable via UI |
| Absorb LMS | ✓ Internal | ✓ External | ✓ | ◑ | ✓ | External LRS config per course |
| Cornerstone | ✓ Internal | ✓ External | ✓ | ◑ | ✓ | Forwarding via Cornerstone’s xAPI engine |
| Moodle 4.x | ✓ Plugin | ✓ Plugin | ✓ | ◑ | ✓ | Logstore xAPI plugin; config per instance |
| TalentLMS | ✓ Basic | ✓ | ✓ | ✗ | ◑ | External LRS supported; limited forwarding |
| LearnUpon | ✓ | ✓ | ✓ | ◑ | ✓ | External LRS per portal |
| SAP Litmos | ◑ | ✓ External | ✓ | ✗ | ◑ | Relies on external LRS for advanced analytics |
| SimpliTrain | ✓ Internal | ✓ External | ✓ | ✓ | ✓ | Statement forwarding to external LRS supported |
| iSpring Learn | ✓ | ✓ | ✓ | ✗ | ◑ | Third-party LRS via xAPI endpoint config |
| SCORM Cloud | ✓ Full | ✓ Forwarding | ✓ | ◑ | ✓ | Statement forwarding: Add Forwarding Path in LRS panel |
xAPI 2.0 adoption in LMS platforms is early as of Q1 2026. Most platforms accept 1.0.3 statements with the 2.0.0 version header as a passthrough. Verify with vendors before relying on 2.0-specific features.
Implementation Steps: Configuring Your LRS with an Enterprise LMS
Step 1, Provision the LRS and Collect Endpoint Credentials
Every LRS exposes a base endpoint URL, all xAPI API calls are relative to this base. The /statements resource is the primary write target. If your LRS documentation shows a base URL of https://lrs.example.com/xapi/, the statements endpoint is https://lrs.example.com/xapi/statements. The trailing slash on the base URL is significant, some LRS platforms treat /xapi and /xapi/ as different routes.
When creating LRS credentials (API key + secret / Basic Auth), configure them with write-only scope for content and authoring tools, they only need to send statements, not read them. Reserve read-only credentials for reporting tools and dashboards. Root / full-access credentials should exist only for LRS administration and statement forwarding targets. This scope principle is defined in xAPI spec Part 3 and is supported differently across LRS platforms, verify your LRS’s credential permission model before distributing credentials to content vendors.
LRS Credential and Header Configuration
// LRS credential configuration, example for authoring tool / LMS connection
Endpoint: https://lrs.example.com/xapi/
Key: Wp9QrKzM3vBx // API key (username for Basic Auth)
Secret: s3cretV@lu3X // API secret (password for Basic Auth)
// HTTP Authorization header constructed by the content / LMS
Authorization: Basic V3A5UXJLek0zdkJ4OnMzY3JldFZAbHUzWA==
// → Base64 of ‘key:secret’, NOT key and secret encoded separately
// Required on every xAPI request, LRS rejects without this
X-Experience-API-Version: 1.0.3
// Statements endpoint for POST (batch) or PUT (single, idempotent)
POST https://lrs.example.com/xapi/statements
Content-Type: application/json
Step 2, Configure the LRS Endpoint in the LMS
Most enterprise LMS platforms have an xAPI / LRS Settings panel in the admin console. The configuration requires: endpoint URL, credential key, credential secret, and in some platforms a credential type selector (Basic Auth vs OAuth vs JWT). Enter these exactly as provided by the LRS, no trailing spaces, no URL encoding applied manually.
For content-level LRS targeting (where individual courses send to a specific LRS rather than the LMS default): update the LRS endpoint in the authoring tool publish settings, not in the LMS configuration. In Articulate Storyline 360, this is under Publish → LMS → Reporting and Tracking → Report to an LRS. In Adobe Captivate (2022+), this is under Preferences → Reporting → TinCan / xAPI. These tool-level settings override any LMS-level LRS default.
Step 3, Validate Connectivity with a Test Statement
Before deploying content, send a test statement manually using Postman or cURL and confirm the LRS returns HTTP 200 (PUT) or 204 (POST with no content-type response body). The ADL xAPI Lab tool (xapi.io/docs/manual/xapiUtilities) provides a browser-based statement sender, use it to validate the endpoint, credentials, and statement format before configuring the LMS.
cURL Test Statement, Endpoint Validation
# cURL test, send minimal xAPI statement via Basic Auth
curl -X POST https://lrs.example.com/xapi/statements \
-H ‘Authorization: Basic V3A5UXJLek0zdkJ4OnMzY3JldFZAbHVlWA==’ \
-H ‘X-Experience-API-Version: 1.0.3’ \
-H ‘Content-Type: application/json’ \
-d ‘{
“actor”: {“account”: {“homePage”: “https://lms.example.com“, “name”: “test-001”}},
“verb”: {“id”: “http://adlnet.gov/expapi/verbs/experienced“},
“object”: {“id”: “https://lms.example.com/activities/test“}
}’
# Expected response: HTTP 200 with statement UUID array
# [“4b5a9b2e-1234-5678-abcd-9e8f7a6b5c4d”]
# HTTP 400 = malformed statement or missing version header
# HTTP 401 = invalid credentials
# HTTP 500 = wrong endpoint URL (LRS-side error)
Step 4, Configure Statement Forwarding (Multi-LRS Architecture)
In SCORM Cloud: LRS tab → Scroll to Statement Forwarding → Add New Forwarding Path. Enter the target LRS endpoint URL, key, and secret. SCORM Cloud forwards all statements received by the source LRS to the target. The target LRS must have write-enabled credentials, configure a write-only credential specifically for statement forwarding to prevent the forwarding source from reading the target LRS.
For enterprise LMS platforms with embedded LRS forwarding (Docebo, Cornerstone): this is configured at the LMS admin level, statements flow from the embedded LRS to the external endpoint automatically after content sessions complete. Verify whether forwarding is real-time or batch (some platforms queue forwarding on a 15-minute interval, which affects near-real-time analytics use cases).
Step 5, LTI-Based LRS Integration into LMS
LTI (Learning Tools Interoperability, IMS Global / 1EdTech standard) provides a secure launch mechanism for embedding external tools, including LRS dashboards, inside the LMS interface. Veracity Learning and OpenLRS implement LTI providers, allowing LRS dashboards, statement viewers, and content launchers to appear natively within Moodle, Canvas, or other LTI-capable LMS platforms. Configure the LRS LTI tool in the LMS’s external tools admin panel with the LTI consumer key, shared secret, and launch URL provided by the LRS vendor.
The Authoring Tool Is the Root Cause of Most LRS 'Missing Statement' Tickets
When statements don’t appear in the LRS, the natural first assumption is an LRS configuration problem, wrong endpoint, wrong credentials, firewall block. In practice, roughly half of ‘missing statement’ cases are caused by the authoring tool, not the LRS.
The two most common authoring-side failures: (1) the course was published as SCORM and uploaded to an xAPI-capable LMS, SCORM packages do not send xAPI statements regardless of what the LMS supports; (2) the LRS endpoint URL in the authoring tool’s publish settings was set during development and pointed to the developer’s personal SCORM Cloud account, not the production LRS.
Before touching LRS configuration, confirm: (a) the course package type is xAPI or cmi5, not SCORM; (b) the endpoint URL in the package’s launch parameters points to the production LRS; (c) the X-Experience-API-Version header is present in the content’s HTTP requests (visible in browser DevTools → Network tab, filtered by the LRS domain). These three checks resolve the majority of ‘we’re not seeing statements’ tickets before any LRS-side investigation is needed.
Common LRS-LMS Integration Issues and Fixes
Issue 1: HTTP 400, ‘X-Experience-API-Version’ Header Missing
Symptom: LRS returns HTTP 400 immediately. Error body: {“error”: “X-Experience-API-Version header was missing or invalid”} or similar.
Root cause: The LRP (content, authoring tool wrapper, or custom integration code) is not including the X-Experience-API-Version header on the HTTP request. This header is REQUIRED by xAPI spec Part 3 on every request. It is not the same as the HTTP Content-Type header. Some early xAPI wrapper libraries (pre-2015) omit this header.
Fix: In custom integration code, add ‘X-Experience-API-Version’: ‘1.0.3’ to every request header object. In authoring tool output: update the xAPI wrapper library to a current version (ADL’s xAPI-launch wrapper on GitHub includes this header correctly). Reference: xAPI Spec Part 3 §6.2.
Issue 2: HTTP 401, Statements Not Authenticated
Symptom: LRS returns HTTP 401. Credentials were copy-pasted from the LRS admin panel and appear correct.
Root cause: Basic Auth encoding error. The Authorization header must be Basic <Base64(key:secret)>, i.e., Base64 encoding of key:secret as a single string with a colon separator, not Base64 of key and Base64 of secret concatenated. A common error in custom implementations is encoding key and secret separately. A second cause: the credential was created with a JWT signing key, which cannot also be used for HTTP Basic Auth; these are separate credential types in some LRS platforms.
Fix: Validate the encoding: echo -n ‘key:secret’ | base64 should produce the exact value used in the Authorization header. If using a JWT key, create a separate Basic Auth credential in the LRS. Reference: Veracity Learning LRS docs (lrs.io/manual).
Issue 3: Statements Arrive but Actor Is ‘anonymous’ or Generic
Symptom: Statements appear in the LRS but all actor fields show “name”: “anonymous” or a generic system identifier. No learner-level reporting is possible.
Root cause: The LMS launch did not inject learner identity into the content’s xAPI configuration. This happens when: (1) content is launched via a direct URL without an LMS launch wrapper; (2) the LMS does not inject the actor parameter into the launch URL for xAPI content (SCORM-era LMS platforms that added xAPI support without updating launch infrastructure); or (3) the cmi5 actor parameter is URL-encoded but the content is not decoding it correctly.
Fix: Confirm the LMS launch URL includes an actor parameter in the form of a URL-encoded JSON agent object. For cmi5, the launch URL must also include endpoint, fetch, registration, and activityId parameters per the cmi5 spec §8.1. If the LMS launch does not inject these, it is not cmi5-conformant, contact the LMS vendor.
Issue 4: TLS/SSL Certificate Verification Error, Statements Not Sent
Symptom: Content appears to function correctly but no statements arrive at the LRS. Browser console shows: ERR_CERT_AUTHORITY_INVALID or Error: unable to verify the first certificate (in Node.js-based launch environments). Affects self-hosted LRS deployments behind a reverse proxy.
Root cause: The LRS is using a self-signed or internally-signed TLS certificate. The browser or Node.js client cannot verify the certificate chain against a trusted CA. xAPI spec Part 3 requires HTTPS, but the TLS certificate must be from a trusted CA for browser-based content to connect without a security exception. This error is common in on-premise LRS deployments behind nginx or Apache with internally-issued certificates. Reference: GitHub issue adlnet/xapi-launch #13.
Fix: Issue a certificate from a public CA (Let’s Encrypt is free and automated). If the environment cannot reach the public internet, ensure the internal CA’s root certificate is installed in all client browsers and Node.js trust stores. Do not use the NODE_TLS_REJECT_UNAUTHORIZED=0 workaround in production, it disables all TLS validation.
Issue 5: Statement Forwarding Duplicates Statements in Target LRS
Symptom: After configuring statement forwarding, statements appear twice in the target LRS, one copy from the original LRP and one copy from the forwarding LRS.
Root cause: The LRP (content / authoring tool) is configured to send statements directly to the target LRS AND the source LRS is also forwarding those statements to the same target. Both channels are active simultaneously.
Fix: Choose one channel: either configure content to send statements to the intermediate LRS only (which forwards to the target), or configure content to send directly to the target LRS (no forwarding required). Do not configure both simultaneously. The xAPI spec allows an LRS to de-duplicate incoming statements by id, a conformant LRS will accept a duplicate statement with the same UUID and treat it as idempotent (HTTP 204, no error). However, some LRS implementations store the duplicate rather than de-duplicate. Confirm your target LRS’s deduplication behaviour before relying on it.
Issue 6: Old xAPI Statement Format (v0.9 / v0.95) Rejected by Strict-Mode LRS
Symptom: Older content launches but statements are rejected by the LRS with HTTP 400. The content was originally published against the Tin Can API pre-release specification (v0.9 or v0.95).
Root cause: Pre-release xAPI specification versions (0.9, 0.95) have slightly different statement structures than the ratified 1.0.x spec. In particular, verb format changed from a plain string (“verb”: “completed”) to an object with an IRI (“verb”: {“id”: “http://adlnet.gov/expapi/verbs/completed“}) between 0.95 and 1.0. Strict-mode LRS platforms reject these statements; some LRS platforms (including Veracity Learning in non-strict mode) automatically translate them.
Fix: Set the LRS to non-strict mode temporarily to import historical statements, then re-enable strict mode. Long term: republish the content from the authoring tool with a current xAPI version target, all major tools (Storyline, Rise, Captivate, Lectora) have supported xAPI 1.0.x for many years. Do not leave the LRS in non-strict mode permanently, as it will accept malformed statements from other sources.
FAQ
LRS Configuration for LMS Admins
Q1. What is the difference between an embedded LRS and a standalone LRS, and do I need both?
An embedded LRS is built into your LMS, Docebo, Absorb, and Cornerstone all include one. It receives statements from content launched inside that LMS automatically. Its limitation is that the query API is typically proprietary: third-party analytics tools cannot read from it directly without LMS-specific API calls, and it only captures statements from content launched through that specific LMS.
A standalone LRS (Watershed, Veracity Learning, SCORM Cloud LRS) has an open xAPI query API, receives statements from multiple source systems, and integrates with BI tools like Tableau or Power BI via its reporting API or statement export. You need both if: your analytics team needs cross-system reporting across multiple LMS platforms or content tools; or if your embedded LRS has an undocumented or inaccessible query interface. Configure statement forwarding from the embedded LRS to the standalone LRS to get statements from LMS-launched content into your analytics system without reconfiguring content packages.
Q2. Does xAPI / LRS configuration affect how SCORM content tracks?
No, SCORM 1.2 and SCORM 2004 4th Edition use the JavaScript Runtime Environment API (API_1484_11 or API) for all communication, not HTTP calls to an LRS. SCORM content is entirely unaffected by LRS endpoint configuration. However, some LMS platforms (SCORM Cloud included) can generate synthetic xAPI statements from SCORM session data and forward those to an LRS, this is a transformation feature of the LMS, not native SCORM behaviour. If you want SCORM completion records in your LRS, enable this synthetic statement generation in the LMS configuration rather than trying to configure the SCORM packages themselves.
Q3. Which xAPI version should I configure my LRS to accept in 2026: 1.0.3 or 2.0?
Configure your LRS to accept both. xAPI 2.0 (IEEE 9274.1.1-2023) is the current specification, but the majority of authoring tools still emit statements with X-Experience-API-Version: 1.0.3 headers as of Q1 2026. A conformant xAPI 2.0 LRS MUST also accept 1.0.3 statements, this is required by the spec. The practical risk is configuring a strict xAPI 2.0-only LRS and discovering that all your existing content packages fail immediately. Accept both version headers, verify that your LRS’s conformance test certificate covers both, and plan content re-publishing to xAPI 2.0 as authoring tools update their output. The ADL LRS test suite and the list of conformant LRS products are maintained at adopters.adlnet.gov/products/all/0.