Importing Courses into Engine

E-learning courses are usually distributed in a self-contained unit called a "package", typically in the form of a ZIP file. Although the structure of a package varies between the different learning standards, you usually don't have to know about these differences when working with Engine.

To launch a course in Engine, you first have to make Engine aware of your course by importing it. For most customers, importing a course into Engine is as simple as uploading the ZIP file package and letting Engine handle the rest.

However, Engine does support a variety of other ways to import your courses, such as providing the path to a course already extracted somewhere, or the URL to download the zip file. You can read about those import methods below, but for now, let's stick to the most common import behaviors.

Importing by ZIP

An important distinction to understand is that Engine does not host your course content files. When Engine imports a course, it will just unzip the course, parse and record its details according to the appropriate learning standard, and drop the course files onto your content server. Unless you want to use Engine's remote hosted player, you should ensure that your content server is on the same domain as Engine, or else Engine's player will be inhibited by browser same-origin policies.

Required Settings

There are a few settings that you'll need to configure for this type of import process to work correctly:

  • FilePathToUploadedZippedPackage - This setting should be the directory that Engine can use as a place to temporarily store the ZIP files while they are being imported. They will be deleted after the import process is completed.
  • FilePathToContentRoot - The directory to which Engine should extract the contents of your courses. Within this directory, a folder for each course will be created. The name of the course folder will be based on your course id, and a subfolder under that for the version (e.g., /mycourseid/0).

    Note: This directory should be hosted by a web server so that all of your course content is accessible to your learners in the browser.

  • WebPathToContentRoot- Engine uses this value to calculate the web path to a course's content once it has been imported. This should be the URL where the directory you specified in FilePathToContentRoot is being hosted. This value is often a relative URL for the current domain (e.g. /courses/content/), but can also be a fully-qualified URL (e.g. if needed.

Posting the ZIP File Directly

Once you've set those values, you can import a course by sending a POST to the /courses/importJobs/upload resource, taking special note of the courseId query string parameter. This parameter should provide a unique identifier for the course being imported.

The body of the request will have the contents of your zip file, and the Content-Type of the request should be multipart/form-data.

Have Engine Download the ZIP File

If you don't want to POST the contents of your course directly to Engine, you can also have the import process fetch the ZIP file itself. To do this, you need to host the course on a web server that Engine can access or on the server's local file system. Once you've done that, you can POST a JSON object (as Content-Type application/json) to /courses/importJobs endpoint with a URL pointing to the location of your zipped course file.

Checking Import Status

It's important to note that when you call the importJobs endpoint through one of the methods above, the course is not immediately ready for use. Since the processing of a course package may take a while, Engine will queue the import job to process it asynchronously and will return a job ID to you in the response.

You should verify that the import job completed successfully before trying to launch it. There are two main ways to do that:

  • Using the job ID that was returned to you, check the status by querying the /courses/importJobs/{importJobId} resource in the API. You may have your UI wait while it periodically checks to see whether the job is finished before continuing.
  • Alternatively, you could have Engine update your application directly when the import is finished. If you set the value of ApiImportResultsPostBackUrl to the URL of an endpoint in your application, then Engine will POST a JSON object describing the results of the course import whenever an import has been completed.

Updating Courses

If at any point you need to update something about your course, you can always upload a new version of the package. To do this, just import your course as normal while specifying the ID of the existing course that you want to update with the course query parameter. You must also specify a second parameter named mayCreateNewVersion with a value of true. That will tell the import process to use the uploaded package as the new version of the specified course.

New registrations against a course will use the latest course version. The behavior for existing registrations, however, is configurable. To configure when existing registrations will switch to using the new version of the course, you will need a setting named WhenToRestartRegistration.

By default, we only move registrations to a new version if the registration has already been marked as complete. Otherwise, it stays on its original course version.

If that behavior doesn't work for your application, you can review the other possible values for WhenToRestartRegistration below:

Setting Value Condition
NEVER Never restart an existing registration
WHEN_EXISTING_REG_IS_COMPLETE_AND_NEWER_PACKAGE_VERSION_EXISTS When a newer version of the associated course package exists and course status is 'Complete'
WHEN_NEWER_PACKAGE_VERSION_EXISTS When a newer version of the associated course package exists
WHEN_EXISTING_REG_IS_COMPLETE When the registration has been completed, regardless of pass/fail status
WHEN_EXISTING_REG_IS_SATISFIED When the overall course status is 'Satisfied'
WHEN_EXISTING_REG_IS_SATISFIED_AND_NEWER_PACKAGE_VERSION_EXISTS When the overall course is satisfied and a newer version of the associated course package exists
WHEN_EXISTING_REG_IS_INCOMPLETE_AND_NEWER_PACKAGE_VERSION_EXISTS When the overall course is incomplete and a newer version of the associated course package exists.
WHEN_EXISTING_REG_IS_FAILED When the overall course is failed.
WHEN_EXISTING_REG_IS_FAILED_AND_NEWER_PACKAGE_VERSION_EXISTS When the overall course is failed and a newer version of of the associated course package exists

One word of caution: whenever Engine moves a registration to a newer version of the course, a new instance of that registration will be created. To a learner, this will effectively reset their progress in the course. Versioning works this way because it's possible that the structure of the new version may not be compatible with the saved data for the old version.

Updating Course Assets

There are times when you may want to update a single file in a course -- maybe to fix a spelling mistake or include a missing image. In that case it may not be desirable to upload the whole course package again and force learners onto a new version of the course. Engine now has an endpoint for updating individual files of the course content.

Just as with importing full course packages, there are multiple ways to update course content assets. You can provide the new file either via a fetch request or via direct upload. Both methods may be used to either update the current course version, or any previous version (through the /courses/{courseiId}/versions endpoints). Updating course assets using either method has no impact on versioning of courses or registration instances/state.

For both methods of updating assets the result of a POST request sent to their respective resources will be a JSON object that indicates the filename and destination of the stored asset.

Posting the Asset File Directly

To import a course asset file directly, send a POST request to the /courses/{courseId}/asset/upload or /courses/{courseId}/versions/{versionId}/asset/upload resource in the API. The body of the request will have the contents of your asset file, and the Content-Type of the request should be multipart/form-data. Along with the file contents, the destination path relative to the root of the course content directory must be specified in the destination parameter.

For additional protection against unintended overwrites or accidental creation of new files that may not be used by the course, the updateAssetPolicy parameter can be provided. By default the policy is lax, which means that Engine will not consider overwrites or new files as problematic.

Fetching the Asset File

An alternative to posting the content of the asset directly, assets that are hosted online can be fetched using a URL instead. To have Engine fetch a content asset, send a POST request to the /courses/{courseId}/asset or /courses/{courseId}/versions/{versionId}/asset resource in the API. Like with posting the asset file directly, the destination parameter specifies the location to save the asset relative to the root of the course content directory and is required. The updateAssetPolicy parameter may also be used as mentioned earlier.

Advanced Import

Importing by Manifest

If your application is already handling the ZIP extraction and the course content is already hosted on a web server, then you can simply point Engine to the manifest of your course and import from that.

To do this, you will POST a JSON object to /courses with the referenceRequest property set to an object containing two values:

  • the url property should point to a SCORM/xAPI/cmi5 manifest or one of the AICC course structure files
  • the webPathToCourse should provide the URL to the root directory of the course's content. This can be an absolute path (e.g., /courses/myCourseOneFolder) as long as it lives on the same domain as Engine's player.


    "referenceRequest": {
        "url": "",
        "webPathToCourse": ""

Since Engine is not handling the actual content files for the course (only the manifest), you must ensure that the content is already available at the path specified.

Unlike the importJobs endpoints, importing by manifest will run synchronously . This means that you won't have to wait for the import job to complete -- the HTTP request will not return until your manifest has been imported.

Ad Hoc Import

You can sometimes have e-learning content that lives on a web server somewhere, but you do not have an actual zip package with a manifest inside it. This is much more likely with standards like AICC or xAPI where the content can communicate directly back to Engine outside the context of a 'player'.

Engine has a way to 'import' a course such as this so that you can launch and track it along with your normally imported course zip packages.

To do this, you will have to POST a JSON object to /courses and include the adHocReferenceRequest property.

Here is an example of what this object could look like and a brief description of what value each of these properties should have.

    "launchUrl": "",
    "webPathToCourse": "",
    "learningStandard": "scorm12",
    "title": "Golf Example - SCORM 1.2"
  • launchUrl - The URL of the launch page of the course.
  • webPathToCourse - The root folder of the course's content. This is folder that a course manifest would go in, if one existed.
  • learningStandard - The learning standard of the course being imported. Acceptable values are aicc, scorm11, scorm12, scorm2004,scorm20042ndedition, scorm20043rdedition, scorm20044thedition, tincan, and cmi5 (values are case insensitive, and Engine will ignore any spaces in the name).
  • title - The title of the course. Will be used as the body of the <title> of the player page in the browser when the course is launched, and possibly displayed in the player UI.

Using the course that you've described in the JSON body, Engine will generate a placeholder manifest in memory and import your course using that. Like importing with a manifest, an ad-hoc import will run synchronously.

Validating a Course Zip or Manifest

Before importing a course for real, some customers like to validate that the to-be-imported course is, in fact, valid and would be imported successfully.

Engine provides a parameter named dryRun that you can pass (with a value of true) to any of our synchronous import methods (i.e., POST to /courses or /courses/upload). When you set this to true, Engine will not extract your course files to FilePathToContentRoot or save any course information to the database. It will only check that the manifest file is valid for its learning standard and that the course would be imported without issue.

Media Content Courses

You can import, play and track launches of video/audio files, and PDF documents similarly to how you would for normal standards-based course packages. Engine automatically collects and stores completion and duration data for .mp4, .mp3 and .pdf files types. You can retrieve that data using the same registration results API or postback that you would use for any other registration.

To import a media course, use the same endpoints described in the above sections with a few minor considerations to differentiate media from zipped course packages.

The resource content types used in the import syntax are one of three types:

  • video/mp4
  • audio/mpeg
  • application/pdf

Posting the Media File Directly

To post a media file directly to Engine, POST to /courses/importJobs/upload. The body of the request contains the media file. You must also include a request header, uploadedContentType, which should be one of the three supported resource content types mentioned earlier.

Optionally, you can add a second item to the request body called contentMetadata, a string of JSON that represents a mediaFileMetadata object.

    "title": "Workplace Violence",
    "description": "A course that teaches one how to identify that different forms of workplace violence."

Have Engine Download the Media File

In contrast, Engine can fetch the media file during the import process. To do this, you need to host the media file on a web server that Engine can access or on the server's local file system. Once you've done that, you can POST a JSON object (as Content-Type application/json) to the /courses/importJobs endpoint.

In addition to a url pointing to the location of your media file, the JSON body should indicate the media resource type you expect Engine to download along with any optional mediaFileMetadata information.

    "url": "http://localhost:80/Courses/SampleVideo.mp4",
    "contentType": "video/mp4",
    "mediaFileMetadata": {
        "title": "Shoe Tying 101",
        "description": "Video introducing how to tie tennis shoes."

Point Engine to the Media File

If your media course content is already hosted on a web server, then you can simply point Engine to the file and have the player load it directly from there when launched.

To do this, POST a JSON object to /courses with the mediaFileReferenceRequest property set to an object containing at least two values:

  • The url property should point to the .mp4, mp3, or .pdf file.
  • The contentType should define the resource type of the file from the URL.
  • Optionally, you may specify an additional mediaFileMeatadata object to describe the media course.
    "mediaFileReferenceRequest": {
        "url": "http://localhost:80/Engine2019Courses/new_courses/math_lecture.mp3",
        "contentType": "audio/mp3",
        "mediaFileMetadata": {
            "title": "Linear Algebra Part 2",
            "description": "Professor Mark's day-2 lecture on advanced linear algebra.",
            "contentLanguage": "en-US",
            "moveOn": "Completed"

Note: For PDF courses, the server that hosts the file must provide the proper CORS headers to allow Engine's player to load the file. Otherwise there will be an error at launch time from the PDF viewer.

Media Content Settings

There are a number of settings that control how the media content looks and behaves. You can view the complete list here in the MediaContent Settings section.

For example, you may require learners to view 50% of a course to attain completion. Or, you may want to enforce a rule that each learner spend at least 30 seconds on each page of a PDF.

Closed Captioning/Subtitles

Courses based on the video handling above can provide subtitle or closed captioning support via WebVTT files. To use this capability a JSON formatted mapping from language codes to WebVTT file URLs needs to be stored to the ContentLangToUrl course configuration setting.

Example configuration value stored as a string:

        "label": "English",
        "src": "/supportFiles/en.vtt",
        "default": true,
        "kind": "subtitles"
        "label": "French",
        "srclang": "fr",
        "src": "/supportFiles/fr.vtt",
        "default": false,
        "kind": "subtitles"

When the video file has been uploaded directly to Engine or has been acquired via the fetch mechanism it may be desired to have the WebVTT files stored along with the video content. When this is desired it is recommended to use the Course Asset Update API to provide the required asset(s). The src value is the result of using the destination property from the response object returned.

YouTube Courses

YouTube content can be imported and played directly via Engine's player and acts much like the video media content courses described above. To import a YouTube video use the same methodology as described in "Point Engine to the Media File" above, but with a YouTube URL and with a contentType property value of youtube in the mediaFileReferenceRequest object. For example:

    "mediaFileReferenceRequest": {
        "url": "",
        "contentType": "youtube",
        "mediaFileMetadata": {

URL Courses

When using the /courses endpoint, you can specify any URL and have Engine create a course that launches it. This is a flexible option if you want to track launches of content that is not available as a learning standard zipped package or a specific media file we support.

Since this could be an external URL to anything, Engine can't track much beyond knowing whether or not the learner launched the course. As soon as the course is launched, Engine automatically marks the registration as Completed.

The JSON body takes a URL property as before, but contentType would simply be url.

    "mediaFileReferenceRequest": {
        "url": "",
        "contentType": "url"

results matching ""

    No results matching ""