{"id":16241,"library":"tincanjs","title":"TinCanJS (Experience API Library)","description":"TinCanJS is a JavaScript library designed for implementing the Experience API (xAPI, formerly Tin Can API) in both web browser and Node.js environments. The current stable version is 0.50.0. While there isn't a fixed release cadence, the project sees regular updates addressing bug fixes, enhancing LRS interaction (e.g., retrieving activity or profile data), and adding new features like end-to-end statement attachment support. Key differentiators include its broad browser compatibility, supporting older IE versions (IE8+ for CORS, IE6+ for non-CORS) and modern browsers, as well as providing a unified API for cross-origin requests. It abstracts away environmental differences, offering a consistent interface for constructing, sending, and retrieving xAPI statements and interacting with Learning Record Stores (LRSs).","status":"active","version":"0.50.0","language":"javascript","source_language":"en","source_url":"https://github.com/RusticiSoftware/TinCanJS","tags":["javascript","tincan","tin can","e-learning","scorm","lrs","experienceapi","experience api","xapi"],"install":[{"cmd":"npm install tincanjs","lang":"bash","label":"npm"},{"cmd":"yarn add tincanjs","lang":"bash","label":"yarn"},{"cmd":"pnpm add tincanjs","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for consistent LRS request API in Node.js environments, providing XHR capabilities.","package":"xhr2","optional":false}],"imports":[{"note":"Primarily a CommonJS library for Node.js. Native ESM imports are not directly supported without a bundler, which would typically wrap the CJS module. The `require` pattern exposes the global `TinCan` object.","wrong":"import TinCan from 'tincanjs';","symbol":"TinCan","correct":"const TinCan = require('tincanjs');"},{"note":"For browser usage, the library is typically included via a script tag, which exposes the `TinCan` object globally. There is no named export for `TinCan` in a browser-native ESM context.","wrong":"import { TinCan } from 'tincanjs';","symbol":"TinCan","correct":"<script src=\"build/tincan-min.js\"></script> // Then access `TinCan` globally"},{"note":"Core classes like `LRS`, `Statement`, `Agent`, `Verb`, `Activity` are exposed as properties of the main `TinCan` object, not as direct named exports.","wrong":"import { LRS } from 'tincanjs';","symbol":"LRS","correct":"const lrs = new TinCan.LRS({ ... });"}],"quickstart":{"code":"const TinCan = require('tincanjs');\n\nconst lrs = new TinCan.LRS({\n    endpoint: process.env.LRS_ENDPOINT ?? 'https://cloud.scorm.com/tc/public/', // Example endpoint\n    username: process.env.LRS_USERNAME ?? 'YOUR_USERNAME',\n    password: process.env.LRS_PASSWORD ?? 'YOUR_PASSWORD',\n    version: '1.0.3' // Specify the xAPI version, e.g., '1.0.3'\n});\n\nconst actor = new TinCan.Agent({\n    name: 'Test User',\n    mbox: 'mailto:test.user@example.com'\n});\n\nconst verb = new TinCan.Verb({\n    id: 'http://adlnet.gov/expapi/verbs/experienced',\n    display: { 'en-US': 'experienced' }\n});\n\nconst activity = new TinCan.Activity({\n    id: 'http://example.com/activities/tincanjs-test',\n    definition: {\n        name: { 'en-US': 'TinCanJS Test Activity' },\n        description: { 'en-US': 'A test activity for TinCanJS quickstart.' }\n    }\n});\n\nconst statement = new TinCan.Statement({\n    actor: actor,\n    verb: verb,\n    object: activity\n});\n\nlrs.saveStatement(statement, function (err, xhr) {\n    if (err) {\n        console.error('Failed to save statement:', err);\n        return;\n    }\n    console.log('Statement saved successfully with ID:', JSON.parse(xhr.responseText)[0]);\n});\n\n// Example of retrieving statements\nlrs.queryStatements({}, function (err, result) {\n    if (err) {\n        console.error('Failed to query statements:', err);\n        return;\n    }\n    console.log('Queried statements count:', result.statements.length);\n});","lang":"javascript","description":"Demonstrates how to initialize an LRS connection and send a basic xAPI statement, followed by querying statements. Uses environment variables for sensitive LRS credentials."},"warnings":[{"fix":"Ensure 'xhr2' is installed via `npm install xhr2`. All LRS interactions in Node.js must use asynchronous (callback-based) methods.","message":"The Node.js environment implementation of TinCanJS has a mandatory dependency on the 'xhr2' package for consistent LRS request APIs. It also does not support synchronous LRS requests due to this underlying dependency.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"If encountering compatibility issues in older browsers, verify polyfill inclusion. For modern browser-only deployments, consider rebuilding the library after commenting out unnecessary polyfills in `Gruntfile.js`.","message":"Supporting older browser versions (e.g., pre-IE10 or specific legacy Chrome/Firefox/Safari versions) may require polyfills for features like TypedArrays, ArrayBuffer with slice, Blob, and TextDecoder/TextEncoder. The default build includes these, but they can be removed to reduce bundle size if targeting modern browsers exclusively.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Upgrade to TinCanJS version 0.34.1 or a later version to resolve the Content-Type header regression issue.","message":"Version 0.34.0 introduced a regression in how configured Content-Type headers were handled for LRS requests, potentially leading to incorrect request headers or LRS rejection. This issue was subsequently fixed in version 0.34.1.","severity":"breaking","affected_versions":"=0.34.0"},{"fix":"Explicitly set the `version` property in the `TinCan.LRS` constructor (e.g., `version: '1.0.3'`). Alternatively, upgrade to version 0.41.1 or higher, which includes improved default version handling for '1.0.2'.","message":"Prior to version 0.41.1, LRS objects instantiated without an explicit version property could experience issues when querying statements, particularly when dealing with newer xAPI versions like '1.0.2', due to missing compatibility table entries.","severity":"gotcha","affected_versions":">=0.1.0, <0.41.1"},{"fix":"Carefully test minified builds after upgrading from versions older than 0.30.0. If discrepancies are observed, compare minified and unminified versions or consider using the unminified library.","message":"The build system was converted to Grunt in version 0.30.0, and the minifier was upgraded. This change, while not intended to alter interfaces or fix bugs, carried a risk of subtle behavioral differences in the minified files, necessitating thorough testing if upgrading from pre-0.30.0 versions and using minified builds.","severity":"gotcha","affected_versions":">=0.30.0, <0.31.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Ensure `<script src=\"build/tincan-min.js\"></script>` is included in your HTML document before any code attempts to use `TinCan`, typically at the end of the `<body>` tag.","cause":"The TinCanJS library script was not successfully loaded in the browser environment, or the global `TinCan` object was accessed before the script fully executed.","error":"ReferenceError: TinCan is not defined"},{"fix":"Install the `xhr2` module by running `npm install xhr2` in your project's root directory.","cause":"The `xhr2` npm package, which is a required peer dependency for TinCanJS to function in Node.js environments, is not installed.","error":"Error: Cannot find module 'xhr2'"},{"fix":"For Node.js, ensure `const TinCan = require('tincanjs');` is at the top of your file. For browsers, verify the `<script>` tag loading `tincanjs` is present and executed. Always access constructors as properties of the `TinCan` object, e.g., `new TinCan.LRS(...)`.","cause":"This error typically occurs when trying to instantiate `LRS` or other core objects before `TinCan` has been properly loaded and assigned, or if attempting to use ES Module import syntax (e.g., `import { LRS } from 'tincanjs'`) which is not supported by this library.","error":"TypeError: TinCan.LRS is not a constructor"},{"fix":"This is an LRS server-side configuration issue, not a client-side library problem. Contact your LRS administrator to ensure that appropriate 'Access-Control-Allow-Origin' headers are configured on the LRS to permit requests from your application's domain.","cause":"The Learning Record Store (LRS) endpoint you are attempting to connect to does not have the necessary Cross-Origin Resource Sharing (CORS) headers configured to allow requests from your web application's origin.","error":"Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."}],"ecosystem":"npm"}